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

LTP GCOV extension - code coverage report
Current view: directory - phar - phar_object.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 2409
Code covered: 78.3 % Executed lines: 1887
Legend: not executed executed

       1                 : /*
       2                 :   +----------------------------------------------------------------------+
       3                 :   | phar php single-file executable PHP extension                        |
       4                 :   +----------------------------------------------------------------------+
       5                 :   | Copyright (c) 2005-2009 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                 : /* $Id: phar_object.c 290647 2009-11-13 00:58:11Z cellog $ */
      21                 : 
      22                 : #include "phar_internal.h"
      23                 : #include "func_interceptors.h"
      24                 : 
      25                 : static zend_class_entry *phar_ce_archive;
      26                 : static zend_class_entry *phar_ce_data;
      27                 : static zend_class_entry *phar_ce_PharException;
      28                 : 
      29                 : #if HAVE_SPL
      30                 : static zend_class_entry *phar_ce_entry;
      31                 : #endif
      32                 : 
      33                 : #if PHP_MAJOR_VERSION > 5 || ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3))
      34                 : # define PHAR_ARG_INFO
      35                 : #else
      36                 : # define PHAR_ARG_INFO static
      37                 : #endif
      38                 : 
      39                 : static int phar_file_type(HashTable *mimes, char *file, char **mime_type TSRMLS_DC) /* {{{ */
      40              39 : {
      41                 :         char *ext;
      42                 :         phar_mime_type *mime;
      43              39 :         ext = strrchr(file, '.');
      44              39 :         if (!ext) {
      45               2 :                 *mime_type = "text/plain";
      46                 :                 /* no file extension = assume text/plain */
      47               2 :                 return PHAR_MIME_OTHER;
      48                 :         }
      49              37 :         ++ext;
      50              37 :         if (SUCCESS != zend_hash_find(mimes, ext, strlen(ext), (void **) &mime)) {
      51               6 :                 *mime_type = "application/octet-stream";
      52               6 :                 return PHAR_MIME_OTHER;
      53                 :         }
      54              31 :         *mime_type = mime->mime;
      55              31 :         return mime->type;
      56                 : }
      57                 : /* }}} */
      58                 : 
      59                 : static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int request_uri_len TSRMLS_DC) /* {{{ */
      60              25 : {
      61                 : #if PHP_MAJOR_VERSION >= 6
      62                 :         int is_unicode = 0;
      63                 : #endif
      64                 :         HashTable *_SERVER;
      65                 :         zval **stuff;
      66                 :         char *path_info;
      67              25 :         int basename_len = strlen(basename);
      68                 :         int code;
      69                 :         zval *temp;
      70                 : 
      71                 :         /* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
      72              25 :         if (!PG(http_globals)[TRACK_VARS_SERVER]) {
      73               0 :                 return;
      74                 :         }
      75                 : 
      76              25 :         _SERVER = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
      77                 : 
      78                 :         /* PATH_INFO and PATH_TRANSLATED should always be munged */
      79                 : #if PHP_MAJOR_VERSION >= 6
      80                 :         if (phar_find_key(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff TSRMLS_CC)) {
      81                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
      82                 :                         is_unicode = 1;
      83                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
      84                 :                 } else {
      85                 :                         is_unicode = 0;
      86                 :                 }
      87                 : #else
      88              25 :         if (SUCCESS == zend_hash_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
      89                 : #endif
      90                 : 
      91              25 :                 path_info = Z_STRVAL_PP(stuff);
      92              25 :                 code = Z_STRLEN_PP(stuff);
      93                 : 
      94              25 :                 if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) {
      95               2 :                         ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1);
      96                 : 
      97               2 :                         MAKE_STD_ZVAL(temp);
      98               2 :                         ZVAL_STRINGL(temp, path_info, code, 0);
      99                 : #if PHP_MAJOR_VERSION >= 6
     100                 :                         if (is_unicode) {
     101                 :                                 zval_string_to_unicode(*stuff TSRMLS_CC);
     102                 :                         }
     103                 : #endif
     104               2 :                         zend_hash_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO"), &temp, sizeof(zval **), NULL);
     105                 :                 }
     106                 :         }
     107                 : 
     108                 : #if PHP_MAJOR_VERSION >= 6
     109                 :         if (phar_find_key(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff TSRMLS_CC)) {
     110                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
     111                 :                         is_unicode = 1;
     112                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
     113                 :                 } else {
     114                 :                         is_unicode = 0;
     115                 :                 }
     116                 : #else
     117              25 :         if (SUCCESS == zend_hash_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
     118                 : #endif
     119                 : 
     120              25 :                 path_info = Z_STRVAL_PP(stuff);
     121              25 :                 code = Z_STRLEN_PP(stuff);
     122              25 :                 Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
     123                 : 
     124              25 :                 MAKE_STD_ZVAL(temp);
     125              25 :                 ZVAL_STRINGL(temp, path_info, code, 0);
     126                 : #if PHP_MAJOR_VERSION >= 6
     127                 :                 if (is_unicode) {
     128                 :                         zval_string_to_unicode(*stuff TSRMLS_CC);
     129                 :                 }
     130                 : #endif
     131              25 :                 zend_hash_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED"), (void *) &temp, sizeof(zval **), NULL);
     132                 :         }
     133                 : 
     134              25 :         if (!PHAR_GLOBALS->phar_SERVER_mung_list) {
     135              19 :                 return;
     136                 :         }
     137                 : 
     138               6 :         if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_REQUEST_URI) {
     139                 : #if PHP_MAJOR_VERSION >= 6
     140                 :                 if (phar_find_key(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff TSRMLS_CC)) {
     141                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
     142                 :                         is_unicode = 1;
     143                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
     144                 :                 } else {
     145                 :                         is_unicode = 0;
     146                 :                 }
     147                 : #else
     148               6 :                 if (SUCCESS == zend_hash_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
     149                 : #endif
     150                 : 
     151               6 :                         path_info = Z_STRVAL_PP(stuff);
     152               6 :                         code = Z_STRLEN_PP(stuff);
     153                 : 
     154               6 :                         if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
     155               6 :                                 ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
     156                 : 
     157               6 :                                 MAKE_STD_ZVAL(temp);
     158               6 :                                 ZVAL_STRINGL(temp, path_info, code, 0);
     159                 : #if PHP_MAJOR_VERSION >= 6
     160                 :                                 if (is_unicode) {
     161                 :                                         zval_string_to_unicode(*stuff TSRMLS_CC);
     162                 :                                 }
     163                 : #endif
     164               6 :                                 zend_hash_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI"), (void *) &temp, sizeof(zval **), NULL);
     165                 :                         }
     166                 :                 }
     167                 :         }
     168                 : 
     169               6 :         if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_PHP_SELF) {
     170                 : #if PHP_MAJOR_VERSION >= 6
     171                 :                 if (phar_find_key(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff TSRMLS_CC)) {
     172                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
     173                 :                         is_unicode = 1;
     174                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
     175                 :                 } else {
     176                 :                         is_unicode = 0;
     177                 :                 }
     178                 : #else
     179               6 :                 if (SUCCESS == zend_hash_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
     180                 : #endif
     181                 : 
     182               6 :                         path_info = Z_STRVAL_PP(stuff);
     183               6 :                         code = Z_STRLEN_PP(stuff);
     184                 : 
     185               6 :                         if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
     186               6 :                                 ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
     187                 : 
     188               6 :                                 MAKE_STD_ZVAL(temp);
     189               6 :                                 ZVAL_STRINGL(temp, path_info, code, 0);
     190                 : #if PHP_MAJOR_VERSION >= 6
     191                 :                                 if (is_unicode) {
     192                 :                                         zval_string_to_unicode(*stuff TSRMLS_CC);
     193                 :                                 }
     194                 : #endif
     195               6 :                                 zend_hash_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF"), (void *) &temp, sizeof(zval **), NULL);
     196                 :                         }
     197                 :                 }
     198                 :         }
     199                 : 
     200               6 :         if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_NAME) {
     201                 : #if PHP_MAJOR_VERSION >= 6
     202                 :                 if (phar_find_key(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff TSRMLS_CC)) {
     203                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
     204                 :                         is_unicode = 1;
     205                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
     206                 :                 } else {
     207                 :                         is_unicode = 0;
     208                 :                 }
     209                 : #else
     210               4 :                 if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
     211                 : #endif
     212                 : 
     213               4 :                         path_info = Z_STRVAL_PP(stuff);
     214               4 :                         code = Z_STRLEN_PP(stuff);
     215               4 :                         ZVAL_STRINGL(*stuff, entry, entry_len, 1);
     216                 : 
     217               4 :                         MAKE_STD_ZVAL(temp);
     218               4 :                         ZVAL_STRINGL(temp, path_info, code, 0);
     219                 : #if PHP_MAJOR_VERSION >= 6
     220                 :                         if (is_unicode) {
     221                 :                                 zval_string_to_unicode(*stuff TSRMLS_CC);
     222                 :                         }
     223                 : #endif
     224               4 :                         zend_hash_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME"), (void *) &temp, sizeof(zval **), NULL);
     225                 :                 }
     226                 :         }
     227                 : 
     228               6 :         if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_FILENAME) {
     229                 : #if PHP_MAJOR_VERSION >= 6
     230                 :                 if (phar_find_key(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff TSRMLS_CC)) {
     231                 :                 if (Z_TYPE_PP(stuff) == IS_UNICODE) {
     232                 :                         is_unicode = 1;
     233                 :                         zval_unicode_to_string(*stuff TSRMLS_CC);
     234                 :                 } else {
     235                 :                         is_unicode = 0;
     236                 :                 }
     237                 : #else
     238               4 :                 if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
     239                 : #endif
     240                 : 
     241               4 :                         path_info = Z_STRVAL_PP(stuff);
     242               4 :                         code = Z_STRLEN_PP(stuff);
     243               4 :                         Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
     244                 : 
     245               4 :                         MAKE_STD_ZVAL(temp);
     246               4 :                         ZVAL_STRINGL(temp, path_info, code, 0);
     247                 : #if PHP_MAJOR_VERSION >= 6
     248                 :                         if (is_unicode) {
     249                 :                                 zval_string_to_unicode(*stuff TSRMLS_CC);
     250                 :                         }
     251                 : #endif
     252               4 :                         zend_hash_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME"), (void *) &temp, sizeof(zval **), NULL);
     253                 :                 }
     254                 :         }
     255                 : }
     256                 : /* }}} */
     257                 : 
     258                 : static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, int entry_len, char *arch, char *basename, char *ru, int ru_len TSRMLS_DC) /* {{{ */
     259              57 : {
     260              57 :         char *name = NULL, buf[8192], *cwd;
     261                 :         zend_syntax_highlighter_ini syntax_highlighter_ini;
     262              57 :         sapi_header_line ctr = {0};
     263                 :         size_t got;
     264              57 :         int dummy = 1, name_len;
     265                 :         zend_file_handle file_handle;
     266                 :         zend_op_array *new_op_array;
     267              57 :         zval *result = NULL;
     268                 :         php_stream *fp;
     269                 :         off_t position;
     270                 : 
     271              57 :         switch (code) {
     272                 :                 case PHAR_MIME_PHPS:
     273              12 :                         efree(basename);
     274                 :                         /* highlight source */
     275              12 :                         if (entry[0] == '/') {
     276               8 :                                 name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
     277                 :                         } else {
     278               4 :                                 name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
     279                 :                         }
     280              12 :                         php_get_highlight_struct(&syntax_highlighter_ini);
     281                 : 
     282              12 :                         highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
     283                 : 
     284              12 :                         efree(name);
     285                 : #ifdef PHP_WIN32
     286                 :                         efree(arch);
     287                 : #endif
     288              12 :                         zend_bailout();
     289                 :                 case PHAR_MIME_OTHER:
     290                 :                         /* send headers, output file contents */
     291              18 :                         efree(basename);
     292              18 :                         ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
     293              18 :                         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     294              18 :                         efree(ctr.line);
     295              18 :                         ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %u", info->uncompressed_filesize);
     296              18 :                         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     297              18 :                         efree(ctr.line);
     298                 : 
     299              18 :                         if (FAILURE == sapi_send_headers(TSRMLS_C)) {
     300               0 :                                 zend_bailout();
     301                 :                         }
     302                 : 
     303                 :                         /* prepare to output  */
     304              18 :                         fp = phar_get_efp(info, 1 TSRMLS_CC);
     305                 : 
     306              18 :                         if (!fp) {
     307                 :                                 char *error;
     308               0 :                                 if (!phar_open_jit(phar, info, &error TSRMLS_CC)) {
     309               0 :                                         if (error) {
     310               0 :                                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
     311               0 :                                                 efree(error);
     312                 :                                         }
     313               0 :                                         return -1;
     314                 :                                 }
     315               0 :                                 fp = phar_get_efp(info, 1 TSRMLS_CC);
     316                 :                         }
     317              18 :                         position = 0;
     318              18 :                         phar_seek_efp(info, 0, SEEK_SET, 0, 1 TSRMLS_CC);
     319                 : 
     320                 :                         do {
     321              20 :                                 got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
     322              20 :                                 if (got > 0) {
     323              20 :                                         PHPWRITE(buf, got);
     324              20 :                                         position += got;
     325              20 :                                         if (position == (off_t) info->uncompressed_filesize) {
     326              18 :                                                 break;
     327                 :                                         }
     328                 :                                 }
     329               2 :                         } while (1);
     330                 : 
     331              18 :                         zend_bailout();
     332                 :                 case PHAR_MIME_PHP:
     333              27 :                         if (basename) {
     334              25 :                                 phar_mung_server_vars(arch, entry, entry_len, basename, ru_len TSRMLS_CC);
     335              25 :                                 efree(basename);
     336                 :                         }
     337                 : 
     338              27 :                         if (entry[0] == '/') {
     339              25 :                                 name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
     340                 :                         } else {
     341               2 :                                 name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
     342                 :                         }
     343                 : 
     344              27 :                         file_handle.type = ZEND_HANDLE_FILENAME;
     345              27 :                         file_handle.handle.fd = 0;
     346              27 :                         file_handle.filename = name;
     347              27 :                         file_handle.opened_path = NULL;
     348              27 :                         file_handle.free_filename = 0;
     349                 : 
     350              27 :                         PHAR_G(cwd) = NULL;
     351              27 :                         PHAR_G(cwd_len) = 0;
     352                 : 
     353              27 :                         if (zend_hash_add(&EG(included_files), name, name_len+1, (void *)&dummy, sizeof(int), NULL) == SUCCESS) {
     354              27 :                                 if ((cwd = zend_memrchr(entry, '/', entry_len))) {
     355              25 :                                         PHAR_G(cwd_init) = 1;
     356              25 :                                         if (entry == cwd) {
     357                 :                                                 /* root directory */
     358              21 :                                                 PHAR_G(cwd_len) = 0;
     359              21 :                                                 PHAR_G(cwd) = NULL;
     360               4 :                                         } else if (entry[0] == '/') {
     361               4 :                                                 PHAR_G(cwd_len) = cwd - (entry + 1);
     362               4 :                                                 PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
     363                 :                                         } else {
     364               0 :                                                 PHAR_G(cwd_len) = cwd - entry;
     365               0 :                                                 PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
     366                 :                                         }
     367                 :                                 }
     368                 : 
     369              27 :                                 new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
     370                 : 
     371              27 :                                 if (!new_op_array) {
     372               0 :                                         zend_hash_del(&EG(included_files), name, name_len+1);
     373                 :                                 }
     374                 : 
     375              27 :                                 zend_destroy_file_handle(&file_handle TSRMLS_CC);
     376                 : 
     377                 :                         } else {
     378               0 :                                 efree(name);
     379               0 :                                 new_op_array = NULL;
     380                 :                         }
     381                 : #ifdef PHP_WIN32
     382                 :                         efree(arch);
     383                 : #endif
     384              27 :                         if (new_op_array) {
     385              27 :                                 EG(return_value_ptr_ptr) = &result;
     386              27 :                                 EG(active_op_array) = new_op_array;
     387                 : 
     388              27 :                                 zend_try {
     389              27 :                                         zend_execute(new_op_array TSRMLS_CC);
     390              24 :                                         if (PHAR_G(cwd)) {
     391               4 :                                                 efree(PHAR_G(cwd));
     392               4 :                                                 PHAR_G(cwd) = NULL;
     393               4 :                                                 PHAR_G(cwd_len) = 0;
     394                 :                                         }
     395                 : 
     396              24 :                                         PHAR_G(cwd_init) = 0;
     397              24 :                                         efree(name);
     398              24 :                                         destroy_op_array(new_op_array TSRMLS_CC);
     399              24 :                                         efree(new_op_array);
     400                 : 
     401                 : 
     402              24 :                                         if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
     403              24 :                                                 zval_ptr_dtor(EG(return_value_ptr_ptr));
     404                 :                                         }
     405               3 :                                 } zend_catch {
     406               3 :                                         if (PHAR_G(cwd)) {
     407               0 :                                                 efree(PHAR_G(cwd));
     408               0 :                                                 PHAR_G(cwd) = NULL;
     409               0 :                                                 PHAR_G(cwd_len) = 0;
     410                 :                                         }
     411                 : 
     412               3 :                                         PHAR_G(cwd_init) = 0;
     413               3 :                                         efree(name);
     414              27 :                                 } zend_end_try();
     415                 : 
     416              27 :                                 zend_bailout();
     417                 :                         }
     418                 : 
     419               0 :                         return PHAR_MIME_PHP;
     420                 :         }
     421               0 :         return -1;
     422                 : }
     423                 : /* }}} */
     424                 : 
     425                 : static void phar_do_403(char *entry, int entry_len TSRMLS_DC) /* {{{ */
     426               4 : {
     427               4 :         sapi_header_line ctr = {0};
     428                 : 
     429               4 :         ctr.response_code = 403;
     430               4 :         ctr.line_len = sizeof("HTTP/1.0 403 Access Denied");
     431               4 :         ctr.line = "HTTP/1.0 403 Access Denied";
     432               4 :         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     433               4 :         sapi_send_headers(TSRMLS_C);
     434               4 :         PHPWRITE("<html>\n <head>\n  <title>Access Denied</title>\n </head>\n <body>\n  <h1>403 - File ", sizeof("<html>\n <head>\n  <title>Access Denied</title>\n </head>\n <body>\n  <h1>403 - File ") - 1);
     435               4 :         PHPWRITE(entry, entry_len);
     436               4 :         PHPWRITE(" Access Denied</h1>\n </body>\n</html>", sizeof(" Access Denied</h1>\n </body>\n</html>") - 1);
     437               4 : }
     438                 : /* }}} */
     439                 : 
     440                 : static void phar_do_404(phar_archive_data *phar, char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */
     441              10 : {
     442              10 :         sapi_header_line ctr = {0};
     443                 :         phar_entry_info *info;
     444                 : 
     445              10 :         if (phar && f404_len) {
     446               2 :                 info = phar_get_entry_info(phar, f404, f404_len, NULL, 1 TSRMLS_CC);
     447                 : 
     448               2 :                 if (info) {
     449               2 :                         phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0 TSRMLS_CC);
     450               0 :                         return;
     451                 :                 }
     452                 :         }
     453                 : 
     454               8 :         ctr.response_code = 404;
     455               8 :         ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
     456               8 :         ctr.line = "HTTP/1.0 404 Not Found";
     457               8 :         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     458               8 :         sapi_send_headers(TSRMLS_C);
     459               8 :         PHPWRITE("<html>\n <head>\n  <title>File Not Found</title>\n </head>\n <body>\n  <h1>404 - File ", sizeof("<html>\n <head>\n  <title>File Not Found</title>\n </head>\n <body>\n  <h1>404 - File ") - 1);
     460               8 :         PHPWRITE(entry, entry_len);
     461               8 :         PHPWRITE(" Not Found</h1>\n </body>\n</html>",  sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
     462                 : }
     463                 : /* }}} */
     464                 : 
     465                 : /* post-process REQUEST_URI and retrieve the actual request URI.  This is for
     466                 :    cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
     467                 :    which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
     468                 : static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len TSRMLS_DC) /* {{{ */
     469              81 : {
     470              81 :         char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
     471              81 :         int e_len = *entry_len - 1, u_len = 0;
     472              81 :         phar_archive_data **pphar = NULL;
     473                 : 
     474                 :         /* we already know we can retrieve the phar if we reach here */
     475              81 :         zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
     476                 : 
     477              81 :         if (!pphar && PHAR_G(manifest_cached)) {
     478               0 :                 zend_hash_find(&cached_phars, fname, fname_len, (void **) &pphar);
     479                 :         }
     480                 : 
     481                 :         do {
     482              87 :                 if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
     483              59 :                         if (u) {
     484               2 :                                 u[0] = '/';
     485               2 :                                 *ru = estrndup(u, u_len+1);
     486               2 :                                 ++u_len;
     487               2 :                                 u[0] = '\0';
     488                 :                         } else {
     489              57 :                                 *ru = NULL;
     490                 :                         }
     491              59 :                         *ru_len = u_len;
     492              59 :                         *entry_len = e_len + 1;
     493              59 :                         return;
     494                 :                 }
     495                 : 
     496              28 :                 if (u) {
     497               4 :                         u1 = strrchr(e, '/');
     498               4 :                         u[0] = '/';
     499               4 :                         saveu = u;
     500               4 :                         e_len += u_len + 1;
     501               4 :                         u = u1;
     502               4 :                         if (!u) {
     503               2 :                                 return;
     504                 :                         }
     505                 :                 } else {
     506              24 :                         u = strrchr(e, '/');
     507              24 :                         if (!u) {
     508              20 :                                 if (saveu) {
     509               0 :                                         saveu[0] = '/';
     510                 :                                 }
     511              20 :                                 return;
     512                 :                         }
     513                 :                 }
     514                 : 
     515               6 :                 u[0] = '\0';
     516               6 :                 u_len = strlen(u + 1);
     517               6 :                 e_len -= u_len + 1;
     518                 : 
     519               6 :                 if (e_len < 0) {
     520               0 :                         if (saveu) {
     521               0 :                                 saveu[0] = '/';
     522                 :                         }
     523               0 :                         return;
     524                 :                 }
     525               6 :         } while (1);
     526                 : }
     527                 : /* }}} */
     528                 : 
     529                 : /* {{{ proto void Phar::running([bool retphar = true])
     530                 :  * return the name of the currently running phar archive.  If the optional parameter
     531                 :  * is set to true, return the phar:// URL to the currently running phar
     532                 :  */
     533                 : PHP_METHOD(Phar, running)
     534              12 : {
     535                 :         char *fname, *arch, *entry;
     536                 :         int fname_len, arch_len, entry_len;
     537              12 :         zend_bool retphar = 1;
     538                 : 
     539              12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &retphar) == FAILURE) {
     540               1 :                 return;
     541                 :         }
     542                 : 
     543              11 :         fname = zend_get_executed_filename(TSRMLS_C);
     544              11 :         fname_len = strlen(fname);
     545                 : 
     546              11 :         if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
     547              10 :                 efree(entry);
     548              10 :                 if (retphar) {
     549               5 :                         RETVAL_STRINGL(fname, arch_len + 7, 1);
     550               5 :                         efree(arch);
     551               5 :                         return;
     552                 :                 } else {
     553               5 :                         RETURN_STRINGL(arch, arch_len, 0);
     554                 :                 }
     555                 :         }
     556                 : 
     557               1 :         RETURN_STRINGL("", 0, 1);
     558                 : }
     559                 : /* }}} */
     560                 : 
     561                 : /* {{{ proto void Phar::mount(string pharpath, string externalfile)
     562                 :  * mount an external file or path to a location within the phar.  This maps
     563                 :  * an external file or directory to a location within the phar archive, allowing
     564                 :  * reference to an external location as if it were within the phar archive.  This
     565                 :  * is useful for writable temp files like databases
     566                 :  */
     567                 : PHP_METHOD(Phar, mount)
     568              20 : {
     569              20 :         char *fname, *arch = NULL, *entry = NULL, *path, *actual;
     570                 :         int fname_len, arch_len, entry_len, path_len, actual_len;
     571                 :         phar_archive_data **pphar;
     572                 : 
     573              20 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) {
     574               0 :                 return;
     575                 :         }
     576                 : 
     577              20 :         fname = zend_get_executed_filename(TSRMLS_C);
     578              20 :         fname_len = strlen(fname);
     579                 : 
     580                 : #ifdef PHP_WIN32
     581                 :         phar_unixify_path_separators(fname, fname_len);
     582                 : #endif
     583                 : 
     584              20 :         if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
     585               6 :                 efree(entry);
     586               6 :                 entry = NULL;
     587                 : 
     588               6 :                 if (path_len > 7 && !memcmp(path, "phar://", 7)) {
     589               1 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path);
     590               1 :                         efree(arch);
     591               1 :                         return;
     592                 :                 }
     593              16 : carry_on2:
     594              16 :                 if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
     595               0 :                         if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, arch, arch_len, (void **)&pphar)) {
     596               0 :                                 if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
     597               0 :                                         goto carry_on;
     598                 :                                 }
     599                 :                         }
     600                 : 
     601               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
     602                 : 
     603               0 :                         if (arch) {
     604               0 :                                 efree(arch);
     605                 :                         }
     606               0 :                         return;
     607                 :                 }
     608              19 : carry_on:
     609              19 :                 if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) {
     610               8 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch);
     611               8 :                         if (path && path == entry) {
     612               5 :                                 efree(entry);
     613                 :                         }
     614                 : 
     615               8 :                         if (arch) {
     616               8 :                                 efree(arch);
     617                 :                         }
     618                 : 
     619               8 :                         return;
     620                 :                 }
     621                 : 
     622              11 :                 if (entry && path && path == entry) {
     623               6 :                         efree(entry);
     624                 :                 }
     625                 : 
     626              11 :                 if (arch) {
     627               8 :                         efree(arch);
     628                 :                 }
     629                 : 
     630              11 :                 return;
     631              14 :         } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
     632               3 :                 goto carry_on;
     633              11 :         } else if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, fname, fname_len, (void **)&pphar)) {
     634               0 :                 if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
     635               0 :                         goto carry_on;
     636                 :                 }
     637                 : 
     638               0 :                 goto carry_on;
     639              11 :         } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
     640              11 :                 path = entry;
     641              11 :                 path_len = entry_len;
     642              11 :                 goto carry_on2;
     643                 :         }
     644                 : 
     645               0 :         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual);
     646                 : }
     647                 : /* }}} */
     648                 : 
     649                 : /* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
     650                 :  * mapPhar for web-based phars. Reads the currently executed file (a phar)
     651                 :  * and registers its manifest. When executed in the CLI or CGI command-line sapi,
     652                 :  * this works exactly like mapPhar().  When executed by a web-based sapi, this
     653                 :  * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
     654                 :  * intended internal file.
     655                 :  */
     656                 : PHP_METHOD(Phar, webPhar)
     657              99 : {
     658              99 :         zval *mimeoverride = NULL, *rewrite = NULL;
     659              99 :         char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
     660              99 :         int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0;
     661              99 :         char *fname, *basename, *path_info, *mime_type = NULL, *entry, *pt;
     662              99 :         int fname_len, entry_len, code, index_php_len = 0, not_cgi;
     663              99 :         phar_archive_data *phar = NULL;
     664                 :         phar_entry_info *info;
     665                 : 
     666              99 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) {
     667               0 :                 return;
     668                 :         }
     669                 : 
     670              99 :         phar_request_initialize(TSRMLS_C);
     671              99 :         fname = zend_get_executed_filename(TSRMLS_C);
     672              99 :         fname_len = strlen(fname);
     673                 : 
     674              99 :         if (phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) != SUCCESS) {
     675               1 :                 if (error) {
     676               1 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
     677               1 :                         efree(error);
     678                 :                 }
     679               1 :                 return;
     680                 :         }
     681                 : 
     682                 :         /* retrieve requested file within phar */
     683              98 :         if (!(SG(request_info).request_method && SG(request_info).request_uri && (!strcmp(SG(request_info).request_method, "GET") || !strcmp(SG(request_info).request_method, "POST")))) {
     684               3 :                 return;
     685                 :         }
     686                 : 
     687                 : #ifdef PHP_WIN32
     688                 :         fname = estrndup(fname, fname_len);
     689                 :         phar_unixify_path_separators(fname, fname_len);
     690                 : #endif
     691              95 :         basename = zend_memrchr(fname, '/', fname_len);
     692                 : 
     693              95 :         if (!basename) {
     694               0 :                 basename = fname;
     695                 :         } else {
     696              95 :                 ++basename;
     697                 :         }
     698                 : 
     699             190 :         if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1))
     700                 :                 || (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) {
     701                 : 
     702              95 :                 if (PG(http_globals)[TRACK_VARS_SERVER]) {
     703              95 :                         HashTable *_server = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
     704                 :                         zval **z_script_name, **z_path_info;
     705                 : 
     706              95 :                         if (SUCCESS != zend_hash_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void**)&z_script_name) ||
     707                 :                                 IS_STRING != Z_TYPE_PP(z_script_name) ||
     708                 :                                 !strstr(Z_STRVAL_PP(z_script_name), basename)) {
     709               0 :                                 return;
     710                 :                         }
     711                 : 
     712             180 :                         if (SUCCESS == zend_hash_find(_server, "PATH_INFO", sizeof("PATH_INFO"), (void**)&z_path_info) &&
     713                 :                                 IS_STRING == Z_TYPE_PP(z_path_info)) {
     714              85 :                                 entry_len = Z_STRLEN_PP(z_path_info);
     715              85 :                                 entry = estrndup(Z_STRVAL_PP(z_path_info), entry_len);
     716              85 :                                 path_info = emalloc(Z_STRLEN_PP(z_script_name) + entry_len + 1);
     717              85 :                                 memcpy(path_info, Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
     718              85 :                                 memcpy(path_info + Z_STRLEN_PP(z_script_name), entry, entry_len + 1);
     719              85 :                                 free_pathinfo = 1;
     720                 :                         } else {
     721              10 :                                 entry_len = 0;
     722              10 :                                 entry = estrndup("", 0);
     723              10 :                                 path_info = Z_STRVAL_PP(z_script_name);
     724                 :                         }
     725                 : 
     726              95 :                         pt = estrndup(Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
     727                 : 
     728                 :                 } else {
     729                 :                         char *testit;
     730                 : 
     731               0 :                         testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
     732               0 :                         if (!(pt = strstr(testit, basename))) {
     733               0 :                                 efree(testit);
     734               0 :                                 return;
     735                 :                         }
     736                 : 
     737               0 :                         path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
     738                 : 
     739               0 :                         if (path_info) {
     740               0 :                                 entry = path_info;
     741               0 :                                 entry_len = strlen(entry);
     742               0 :                                 spprintf(&path_info, 0, "%s%s", testit, path_info);
     743               0 :                                 free_pathinfo = 1;
     744                 :                         } else {
     745               0 :                                 path_info = testit;
     746               0 :                                 free_pathinfo = 1;
     747               0 :                                 entry = estrndup("", 0);
     748               0 :                                 entry_len = 0;
     749                 :                         }
     750                 : 
     751               0 :                         pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
     752                 :                 }
     753              95 :                 not_cgi = 0;
     754                 :         } else {
     755               0 :                 path_info = SG(request_info).request_uri;
     756                 : 
     757               0 :                 if (!(pt = strstr(path_info, basename))) {
     758                 :                         /* this can happen with rewrite rules - and we have no idea what to do then, so return */
     759               0 :                         return;
     760                 :                 }
     761                 : 
     762               0 :                 entry_len = strlen(path_info);
     763               0 :                 entry_len -= (pt - path_info) + (fname_len - (basename - fname));
     764               0 :                 entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
     765                 : 
     766               0 :                 pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
     767               0 :                 not_cgi = 1;
     768                 :         }
     769                 : 
     770              95 :         if (rewrite) {
     771                 :                 zend_fcall_info fci;
     772                 :                 zend_fcall_info_cache fcc;
     773                 :                 zval *params, *retval_ptr, **zp[1];
     774                 : 
     775              20 :                 MAKE_STD_ZVAL(params);
     776              20 :                 ZVAL_STRINGL(params, entry, entry_len, 1);
     777              20 :                 zp[0] = &params;
     778                 : 
     779                 : #if PHP_VERSION_ID < 50300
     780                 :                 if (FAILURE == zend_fcall_info_init(rewrite, &fci, &fcc TSRMLS_CC)) {
     781                 : #else
     782              20 :                 if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
     783                 : #endif
     784               2 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback");
     785                 : 
     786               2 :                         if (free_pathinfo) {
     787               0 :                                 efree(path_info);
     788                 :                         }
     789                 : 
     790               2 :                         return;
     791                 :                 }
     792                 : 
     793              18 :                 fci.param_count = 1;
     794              18 :                 fci.params = zp;
     795                 : #if PHP_VERSION_ID < 50300
     796                 :                 ++(params->refcount);
     797                 : #else
     798              18 :                 Z_ADDREF_P(params);
     799                 : #endif
     800              18 :                 fci.retval_ptr_ptr = &retval_ptr;
     801                 : 
     802              18 :                 if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
     803               2 :                         if (!EG(exception)) {
     804               2 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback");
     805                 :                         }
     806                 : 
     807               2 :                         if (free_pathinfo) {
     808               0 :                                 efree(path_info);
     809                 :                         }
     810                 : 
     811               2 :                         return;
     812                 :                 }
     813                 : 
     814              16 :                 if (!fci.retval_ptr_ptr || !retval_ptr) {
     815               0 :                         if (free_pathinfo) {
     816               0 :                                 efree(path_info);
     817                 :                         }
     818               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
     819               0 :                         return;
     820                 :                 }
     821                 : 
     822              16 :                 switch (Z_TYPE_P(retval_ptr)) {
     823                 : #if PHP_VERSION_ID >= 60000
     824                 :                         case IS_UNICODE:
     825                 :                                 zval_unicode_to_string(retval_ptr TSRMLS_CC);
     826                 :                                 /* break intentionally omitted */
     827                 : #endif
     828                 :                         case IS_STRING:
     829              10 :                                 efree(entry);
     830                 : 
     831              10 :                                 if (fci.retval_ptr_ptr != &retval_ptr) {
     832               0 :                                         entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr));
     833               0 :                                         entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr);
     834                 :                                 } else {
     835              10 :                                         entry = Z_STRVAL_P(retval_ptr);
     836              10 :                                         entry_len = Z_STRLEN_P(retval_ptr);
     837                 :                                 }
     838                 : 
     839              10 :                                 break;
     840                 :                         case IS_BOOL:
     841               4 :                                 phar_do_403(entry, entry_len TSRMLS_CC);
     842                 : 
     843               4 :                                 if (free_pathinfo) {
     844               4 :                                         efree(path_info);
     845                 :                                 }
     846                 : 
     847               4 :                                 zend_bailout();
     848               0 :                                 return;
     849                 :                         default:
     850               2 :                                 efree(retval_ptr);
     851                 : 
     852               2 :                                 if (free_pathinfo) {
     853               0 :                                         efree(path_info);
     854                 :                                 }
     855                 : 
     856               2 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
     857               2 :                                 return;
     858                 :                 }
     859                 :         }
     860                 : 
     861              85 :         if (entry_len) {
     862              81 :                 phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC);
     863                 :         }
     864                 : 
     865              85 :         if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
     866              16 :                 efree(entry);
     867                 :                 /* direct request */
     868              16 :                 if (index_php_len) {
     869               8 :                         entry = index_php;
     870               8 :                         entry_len = index_php_len;
     871               8 :                         if (entry[0] != '/') {
     872               4 :                                 spprintf(&entry, 0, "/%s", index_php);
     873               4 :                                 ++entry_len;
     874                 :                         }
     875                 :                 } else {
     876                 :                         /* assume "index.php" is starting point */
     877               8 :                         entry = estrndup("/index.php", sizeof("/index.php"));
     878               8 :                         entry_len = sizeof("/index.php")-1;
     879                 :                 }
     880                 : 
     881              16 :                 if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
     882                 :                         (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
     883               4 :                         phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
     884                 : 
     885               4 :                         if (free_pathinfo) {
     886               4 :                                 efree(path_info);
     887                 :                         }
     888                 : 
     889               4 :                         zend_bailout();
     890                 :                 } else {
     891                 :                         char *tmp, sa;
     892              12 :                         sapi_header_line ctr = {0};
     893              12 :                         ctr.response_code = 301;
     894              12 :                         ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")+1;
     895              12 :                         ctr.line = "HTTP/1.1 301 Moved Permanently";
     896              12 :                         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     897                 : 
     898              12 :                         if (not_cgi) {
     899               0 :                                 tmp = strstr(path_info, basename) + fname_len;
     900               0 :                                 sa = *tmp;
     901               0 :                                 *tmp = '\0';
     902                 :                         }
     903                 : 
     904              12 :                         ctr.response_code = 0;
     905                 : 
     906              12 :                         if (path_info[strlen(path_info)-1] == '/') {
     907               8 :                                 ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
     908                 :                         } else {
     909               4 :                                 ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
     910                 :                         }
     911                 : 
     912              12 :                         if (not_cgi) {
     913               0 :                                 *tmp = sa;
     914                 :                         }
     915                 : 
     916              12 :                         if (free_pathinfo) {
     917               8 :                                 efree(path_info);
     918                 :                         }
     919                 : 
     920              12 :                         sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
     921              12 :                         sapi_send_headers(TSRMLS_C);
     922              12 :                         efree(ctr.line);
     923              12 :                         zend_bailout();
     924                 :                 }
     925                 :         }
     926                 : 
     927              69 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
     928                 :                 (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
     929               6 :                 phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
     930                 : #ifdef PHP_WIN32
     931                 :                 efree(fname);
     932                 : #endif
     933               4 :                 zend_bailout();
     934                 :         }
     935                 : 
     936              63 :         if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
     937              34 :                 char *ext = zend_memrchr(entry, '.', entry_len);
     938                 :                 zval **val;
     939                 : 
     940              34 :                 if (ext) {
     941              32 :                         ++ext;
     942                 : 
     943                 : #if PHP_MAJOR_VERSION >= 6
     944                 :                         if (phar_find_key(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val TSRMLS_CC)) {
     945                 : #else
     946              32 :                         if (SUCCESS == zend_hash_find(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val)) {
     947                 : #endif
     948              24 :                                 switch (Z_TYPE_PP(val)) {
     949                 :                                         case IS_LONG:
     950              16 :                                                 if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
     951              12 :                                                         mime_type = "";
     952              12 :                                                         code = Z_LVAL_PP(val);
     953                 :                                                 } else {
     954               4 :                                                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed");
     955                 : #ifdef PHP_WIN32
     956                 :                                                         efree(fname);
     957                 : #endif
     958               4 :                                                         RETURN_FALSE;
     959                 :                                                 }
     960              12 :                                                 break;
     961                 : #if PHP_MAJOR_VERSION >= 6
     962                 :                                         case IS_UNICODE:
     963                 :                                                 zval_unicode_to_string(*(val) TSRMLS_CC);
     964                 :                                                 /* break intentionally omitted */
     965                 : #endif
     966                 :                                         case IS_STRING:
     967               4 :                                                 mime_type = Z_STRVAL_PP(val);
     968               4 :                                                 code = PHAR_MIME_OTHER;
     969               4 :                                                 break;
     970                 :                                         default:
     971               4 :                                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed");
     972                 : #ifdef PHP_WIN32
     973                 :                                                 efree(fname);
     974                 : #endif
     975               4 :                                                 RETURN_FALSE;
     976                 :                                 }
     977                 :                         }
     978                 :                 }
     979                 :         }
     980                 : 
     981              55 :         if (!mime_type) {
     982              39 :                 code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type TSRMLS_CC);
     983                 :         }
     984              55 :         ret = phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len TSRMLS_CC);
     985                 : }
     986                 : /* }}} */
     987                 : 
     988                 : /* {{{ proto void Phar::mungServer(array munglist)
     989                 :  * Defines a list of up to 4 $_SERVER variables that should be modified for execution
     990                 :  * to mask the presence of the phar archive.  This should be used in conjunction with
     991                 :  * Phar::webPhar(), and has no effect otherwise
     992                 :  * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME
     993                 :  */
     994                 : PHP_METHOD(Phar, mungServer)
     995              19 : {
     996                 :         zval *mungvalues;
     997                 : 
     998              19 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) {
     999               1 :                 return;
    1000                 :         }
    1001                 : 
    1002              18 :         if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) {
    1003               4 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
    1004               4 :                 return;
    1005                 :         }
    1006                 : 
    1007              14 :         if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
    1008               4 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
    1009               4 :                 return;
    1010                 :         }
    1011                 : 
    1012              10 :         phar_request_initialize(TSRMLS_C);
    1013                 : 
    1014              30 :         for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mungvalues)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mungvalues)); zend_hash_move_forward(Z_ARRVAL_P(mungvalues))) {
    1015              24 :                 zval **data = NULL;
    1016                 : #if PHP_MAJOR_VERSION >= 6
    1017                 :                 zval *unicopy = NULL;
    1018                 : #endif
    1019                 : 
    1020              24 :                 if (SUCCESS != zend_hash_get_current_data(Z_ARRVAL_P(mungvalues), (void **) &data)) {
    1021               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "unable to retrieve array value in Phar::mungServer()");
    1022               0 :                         return;
    1023                 :                 }
    1024                 : 
    1025                 : #if PHP_MAJOR_VERSION >= 6
    1026                 :                 if (Z_TYPE_PP(data) == IS_UNICODE) {
    1027                 :                         MAKE_STD_ZVAL(unicopy);
    1028                 :                         *unicopy = **data;
    1029                 :                         zval_copy_ctor(unicopy);
    1030                 :                         INIT_PZVAL(unicopy);
    1031                 :                         zval_unicode_to_string(unicopy TSRMLS_CC);
    1032                 :                         data = &unicopy;
    1033                 :                 }
    1034                 : #endif
    1035                 : 
    1036              24 :                 if (Z_TYPE_PP(data) != IS_STRING) {
    1037               4 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
    1038               4 :                         return;
    1039                 :                 }
    1040                 : 
    1041              20 :                 if (Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
    1042               6 :                         PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_PHP_SELF;
    1043                 :                 }
    1044                 : 
    1045              20 :                 if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) {
    1046              10 :                         if (!strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
    1047               6 :                                 PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_REQUEST_URI;
    1048                 :                         }
    1049              10 :                         if (!strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
    1050               4 :                                 PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_NAME;
    1051                 :                         }
    1052                 :                 }
    1053                 : 
    1054              20 :                 if (Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
    1055               4 :                         PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_FILENAME;
    1056                 :                 }
    1057                 : #if PHP_MAJOR_VERSION >= 6
    1058                 :                 if (unicopy) {
    1059                 :                         zval_ptr_dtor(&unicopy);
    1060                 :                 }
    1061                 : #endif
    1062                 :         }
    1063                 : }
    1064                 : /* }}} */
    1065                 : 
    1066                 : /* {{{ proto void Phar::interceptFileFuncs()
    1067                 :  * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
    1068                 :  * and return stat on files within the phar for relative paths
    1069                 :  *
    1070                 :  * Once called, this cannot be reversed, and continue until the end of the request.
    1071                 :  *
    1072                 :  * This allows legacy scripts to be pharred unmodified
    1073                 :  */
    1074                 : PHP_METHOD(Phar, interceptFileFuncs)
    1075              17 : {
    1076              17 :         phar_intercept_functions(TSRMLS_C);
    1077              17 : }
    1078                 : /* }}} */
    1079                 : 
    1080                 : /* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]])
    1081                 :  * Return a stub that can be used to run a phar-based archive without the phar extension
    1082                 :  * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile
    1083                 :  * is the web startup filename, and also defaults to "index.php"
    1084                 :  */
    1085                 : PHP_METHOD(Phar, createDefaultStub)
    1086               9 : {
    1087               9 :         char *index = NULL, *webindex = NULL, *stub, *error;
    1088               9 :         int index_len = 0, webindex_len = 0;
    1089                 :         size_t stub_len;
    1090                 : 
    1091               9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
    1092               1 :                 return;
    1093                 :         }
    1094                 : 
    1095               8 :         stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
    1096                 : 
    1097               8 :         if (error) {
    1098               2 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    1099               2 :                 efree(error);
    1100               2 :                 return;
    1101                 :         }
    1102               6 :         RETURN_STRINGL(stub, stub_len, 0);
    1103                 : }
    1104                 : /* }}} */
    1105                 : 
    1106                 : /* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
    1107                 :  * Reads the currently executed file (a phar) and registers its manifest */
    1108                 : PHP_METHOD(Phar, mapPhar)
    1109              36 : {
    1110              36 :         char *alias = NULL, *error;
    1111              36 :         int alias_len = 0;
    1112              36 :         long dataoffset = 0;
    1113                 : 
    1114              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
    1115               1 :                 return;
    1116                 :         }
    1117                 : 
    1118              35 :         phar_request_initialize(TSRMLS_C);
    1119                 : 
    1120              35 :         RETVAL_BOOL(phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) == SUCCESS);
    1121                 : 
    1122              35 :         if (error) {
    1123               9 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    1124               9 :                 efree(error);
    1125                 :         }
    1126                 : } /* }}} */
    1127                 : 
    1128                 : /* {{{ proto mixed Phar::loadPhar(string filename [, string alias])
    1129                 :  * Loads any phar archive with an alias */
    1130                 : PHP_METHOD(Phar, loadPhar)
    1131               8 : {
    1132               8 :         char *fname, *alias = NULL, *error;
    1133               8 :         int fname_len, alias_len = 0;
    1134                 : 
    1135               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) {
    1136               1 :                 return;
    1137                 :         }
    1138                 : 
    1139               7 :         phar_request_initialize(TSRMLS_C);
    1140                 : 
    1141               7 :         RETVAL_BOOL(phar_open_from_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS);
    1142                 : 
    1143               7 :         if (error) {
    1144               2 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    1145               2 :                 efree(error);
    1146                 :         }
    1147                 : } /* }}} */
    1148                 : 
    1149                 : /* {{{ proto string Phar::apiVersion()
    1150                 :  * Returns the api version */
    1151                 : PHP_METHOD(Phar, apiVersion)
    1152               1 : {
    1153               1 :         RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1, 1);
    1154                 : }
    1155                 : /* }}}*/
    1156                 : 
    1157                 : /* {{{ proto bool Phar::canCompress([int method])
    1158                 :  * Returns whether phar extension supports compression using zlib/bzip2 */
    1159                 : PHP_METHOD(Phar, canCompress)
    1160               4 : {
    1161               4 :         long method = 0;
    1162                 : 
    1163               4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
    1164               1 :                 return;
    1165                 :         }
    1166                 : 
    1167               3 :         phar_request_initialize(TSRMLS_C);
    1168               3 :         switch (method) {
    1169                 :         case PHAR_ENT_COMPRESSED_GZ:
    1170               1 :                 if (PHAR_G(has_zlib)) {
    1171               1 :                         RETURN_TRUE;
    1172                 :                 } else {
    1173               0 :                         RETURN_FALSE;
    1174                 :                 }
    1175                 :         case PHAR_ENT_COMPRESSED_BZ2:
    1176               1 :                 if (PHAR_G(has_bz2)) {
    1177               1 :                         RETURN_TRUE;
    1178                 :                 } else {
    1179               0 :                         RETURN_FALSE;
    1180                 :                 }
    1181                 :         default:
    1182               1 :                 if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) {
    1183               1 :                         RETURN_TRUE;
    1184                 :                 } else {
    1185               0 :                         RETURN_FALSE;
    1186                 :                 }
    1187                 :         }
    1188                 : }
    1189                 : /* }}} */
    1190                 : 
    1191                 : /* {{{ proto bool Phar::canWrite()
    1192                 :  * Returns whether phar extension supports writing and creating phars */
    1193                 : PHP_METHOD(Phar, canWrite)
    1194               5 : {
    1195               5 :         RETURN_BOOL(!PHAR_G(readonly));
    1196                 : }
    1197                 : /* }}} */
    1198                 : 
    1199                 : /* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
    1200                 :  * Returns whether the given filename is a valid phar filename */
    1201                 : PHP_METHOD(Phar, isValidPharFilename)
    1202              37 : {
    1203                 :         char *fname;
    1204                 :         const char *ext_str;
    1205                 :         int fname_len, ext_len, is_executable;
    1206              37 :         zend_bool executable = 1;
    1207                 : 
    1208              37 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &fname, &fname_len, &executable) == FAILURE) {
    1209               1 :                 return;
    1210                 :         }
    1211                 : 
    1212              36 :         is_executable = executable;
    1213              36 :         RETVAL_BOOL(phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, is_executable, 2, 1 TSRMLS_CC) == SUCCESS);
    1214                 : }
    1215                 : /* }}} */
    1216                 : 
    1217                 : #if HAVE_SPL
    1218                 : /**
    1219                 :  * from spl_directory
    1220                 :  */
    1221                 : static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
    1222             429 : {
    1223             429 :         phar_archive_data *phar = (phar_archive_data *) object->oth;
    1224                 : 
    1225             429 :         if (!phar->is_persistent) {
    1226             429 :                 phar_archive_delref(phar TSRMLS_CC);
    1227                 :         }
    1228                 : 
    1229             429 :         object->oth = NULL;
    1230             429 : }
    1231                 : /* }}} */
    1232                 : 
    1233                 : /**
    1234                 :  * from spl_directory
    1235                 :  */
    1236                 : static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC) /* {{{ */
    1237               0 : {
    1238               0 :         phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
    1239                 : 
    1240               0 :         if (!phar_data->is_persistent) {
    1241               0 :                 ++(phar_data->refcount);
    1242                 :         }
    1243               0 : }
    1244                 : /* }}} */
    1245                 : 
    1246                 : static spl_other_handler phar_spl_foreign_handler = {
    1247                 :         phar_spl_foreign_dtor,
    1248                 :         phar_spl_foreign_clone
    1249                 : };
    1250                 : #endif /* HAVE_SPL */
    1251                 : 
    1252                 : /* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
    1253                 :  * Construct a Phar archive object
    1254                 :  * {{{ proto void PharData::__construct(string fname [[, int flags [, string alias]], int file format = Phar::TAR])
    1255                 :  * Construct a PharData archive object
    1256                 :  */
    1257                 : PHP_METHOD(Phar, __construct)
    1258             492 : {
    1259                 : #if !HAVE_SPL
    1260                 :         zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
    1261                 : #else
    1262             492 :         char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname;
    1263             492 :         int fname_len, alias_len = 0, arch_len, entry_len, is_data;
    1264                 : #if PHP_VERSION_ID < 50300
    1265                 :         long flags = 0;
    1266                 : #else
    1267             492 :         long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
    1268                 : #endif
    1269             492 :         long format = 0;
    1270                 :         phar_archive_object *phar_obj;
    1271                 :         phar_archive_data   *phar_data;
    1272             492 :         zval *zobj = getThis(), arg1, arg2;
    1273                 : 
    1274             492 :         phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1275                 : 
    1276             492 :         is_data = instanceof_function(Z_OBJCE_P(zobj), phar_ce_data TSRMLS_CC);
    1277                 : 
    1278             492 :         if (is_data) {
    1279              93 :                 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!l", &fname, &fname_len, &flags, &alias, &alias_len, &format) == FAILURE) {
    1280               0 :                         return;
    1281                 :                 }
    1282                 :         } else {
    1283             399 :                 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) {
    1284               1 :                         return;
    1285                 :                 }
    1286                 :         }
    1287                 : 
    1288             491 :         if (phar_obj->arc.archive) {
    1289               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
    1290               1 :                 return;
    1291                 :         }
    1292                 : 
    1293             490 :         save_fname = fname;
    1294             490 :         if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2 TSRMLS_CC)) {
    1295                 :                 /* use arch (the basename for the archive) for fname instead of fname */
    1296                 :                 /* this allows support for RecursiveDirectoryIterator of subdirectories */
    1297                 : #ifdef PHP_WIN32
    1298                 :                 phar_unixify_path_separators(arch, arch_len);
    1299                 : #endif
    1300             483 :                 fname = arch;
    1301             483 :                 fname_len = arch_len;
    1302                 : #ifdef PHP_WIN32
    1303                 :         } else {
    1304                 :                 arch = estrndup(fname, fname_len);
    1305                 :                 arch_len = fname_len;
    1306                 :                 fname = arch;
    1307                 :                 phar_unixify_path_separators(arch, arch_len);
    1308                 : #endif
    1309                 :         }
    1310                 : 
    1311             490 :         if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
    1312                 : 
    1313              61 :                 if (fname == arch && fname != save_fname) {
    1314              54 :                         efree(arch);
    1315              54 :                         fname = save_fname;
    1316                 :                 }
    1317                 : 
    1318              61 :                 if (entry) {
    1319              54 :                         efree(entry);
    1320                 :                 }
    1321                 : 
    1322              61 :                 if (error) {
    1323              61 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    1324                 :                                 "%s", error);
    1325              61 :                         efree(error);
    1326                 :                 } else {
    1327               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    1328                 :                                 "Phar creation or opening failed");
    1329                 :                 }
    1330                 : 
    1331              61 :                 return;
    1332                 :         }
    1333                 : 
    1334             429 :         if (is_data && phar_data->is_tar && phar_data->is_brandnew && format == PHAR_FORMAT_ZIP) {
    1335               0 :                 phar_data->is_zip = 1;
    1336               0 :                 phar_data->is_tar = 0;
    1337                 :         }
    1338                 : 
    1339             429 :         if (fname == arch) {
    1340             429 :                 efree(arch);
    1341             429 :                 fname = save_fname;
    1342                 :         }
    1343                 : 
    1344             429 :         if ((is_data && !phar_data->is_data) || (!is_data && phar_data->is_data)) {
    1345               0 :                 if (is_data) {
    1346               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    1347                 :                                 "PharData class can only be used for non-executable tar and zip archives");
    1348                 :                 } else {
    1349               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    1350                 :                                 "Phar class can only be used for executable tar and zip archives");
    1351                 :                 }
    1352               0 :                 efree(entry);
    1353               0 :                 return;
    1354                 :         }
    1355                 : 
    1356             429 :         is_data = phar_data->is_data;
    1357                 : 
    1358             429 :         if (!phar_data->is_persistent) {
    1359             427 :                 ++(phar_data->refcount);
    1360                 :         }
    1361                 : 
    1362             429 :         phar_obj->arc.archive = phar_data;
    1363             429 :         phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
    1364                 : 
    1365             429 :         if (entry) {
    1366             429 :                 fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry);
    1367             429 :                 efree(entry);
    1368                 :         } else {
    1369               0 :                 fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
    1370                 :         }
    1371                 : 
    1372             429 :         INIT_PZVAL(&arg1);
    1373             429 :         ZVAL_STRINGL(&arg1, fname, fname_len, 0);
    1374             429 :         INIT_PZVAL(&arg2);
    1375             429 :         ZVAL_LONG(&arg2, flags);
    1376                 : 
    1377             429 :         zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj), 
    1378                 :                 &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
    1379                 : 
    1380             429 :         if (!phar_data->is_persistent) {
    1381             427 :                 phar_obj->arc.archive->is_data = is_data;
    1382               2 :         } else if (!EG(exception)) {
    1383                 :                 /* register this guy so we can modify if necessary */
    1384               2 :                 zend_hash_add(&PHAR_GLOBALS->phar_persist_map, (const char *) phar_obj->arc.archive, sizeof(phar_obj->arc.archive), (void *) &phar_obj, sizeof(phar_archive_object **), NULL);
    1385                 :         }
    1386                 : 
    1387             429 :         phar_obj->spl.info_class = phar_ce_entry;
    1388             429 :         efree(fname);
    1389                 : #endif /* HAVE_SPL */
    1390                 : }
    1391                 : /* }}} */
    1392                 : 
    1393                 : /* {{{ proto array Phar::getSupportedSignatures()
    1394                 :  * Return array of supported signature types
    1395                 :  */
    1396                 : PHP_METHOD(Phar, getSupportedSignatures)
    1397              10 : {
    1398              10 :         array_init(return_value);
    1399                 : 
    1400              10 :         add_next_index_stringl(return_value, "MD5", 3, 1);
    1401              10 :         add_next_index_stringl(return_value, "SHA-1", 5, 1);
    1402                 : #ifdef PHAR_HASH_OK
    1403              10 :         add_next_index_stringl(return_value, "SHA-256", 7, 1);
    1404              10 :         add_next_index_stringl(return_value, "SHA-512", 7, 1);
    1405                 : #endif
    1406                 : #if PHAR_HAVE_OPENSSL
    1407              10 :         add_next_index_stringl(return_value, "OpenSSL", 7, 1);
    1408                 : #else
    1409                 :         if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
    1410                 :                 add_next_index_stringl(return_value, "OpenSSL", 7, 1);
    1411                 :         }
    1412                 : #endif
    1413              10 : }
    1414                 : /* }}} */
    1415                 : 
    1416                 : /* {{{ proto array Phar::getSupportedCompression()
    1417                 :  * Return array of supported comparession algorithms
    1418                 :  */
    1419                 : PHP_METHOD(Phar, getSupportedCompression)
    1420               1 : {
    1421               1 :         array_init(return_value);
    1422               1 :         phar_request_initialize(TSRMLS_C);
    1423                 : 
    1424               1 :         if (PHAR_G(has_zlib)) {
    1425               1 :                 add_next_index_stringl(return_value, "GZ", 2, 1);
    1426                 :         }
    1427                 : 
    1428               1 :         if (PHAR_G(has_bz2)) {
    1429               1 :                 add_next_index_stringl(return_value, "BZIP2", 5, 1);
    1430                 :         }
    1431               1 : }
    1432                 : /* }}} */
    1433                 : 
    1434                 : /* {{{ proto array Phar::unlinkArchive(string archive)
    1435                 :  * Completely remove a phar archive from memory and disk
    1436                 :  */
    1437                 : PHP_METHOD(Phar, unlinkArchive)
    1438              13 : {
    1439                 :         char *fname, *error, *zname, *arch, *entry;
    1440                 :         int fname_len, zname_len, arch_len, entry_len;
    1441                 :         phar_archive_data *phar;
    1442                 : 
    1443              13 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    1444               1 :                 RETURN_FALSE;
    1445                 :         }
    1446                 : 
    1447              12 :         if (!fname_len) {
    1448               1 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"\"");
    1449               1 :                 return;
    1450                 :         }
    1451                 : 
    1452              11 :         if (FAILURE == phar_open_from_filename(fname, fname_len, NULL, 0, REPORT_ERRORS, &phar, &error TSRMLS_CC)) {
    1453               2 :                 if (error) {
    1454               2 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\": %s", fname, error);
    1455               2 :                         efree(error);
    1456                 :                 } else {
    1457               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\"", fname);
    1458                 :                 }
    1459               2 :                 return;
    1460                 :         }
    1461                 : 
    1462               9 :         zname = zend_get_executed_filename(TSRMLS_C);
    1463               9 :         zname_len = strlen(zname);
    1464                 : 
    1465               9 :         if (zname_len > 7 && !memcmp(zname, "phar://", 7) && SUCCESS == phar_split_fname(zname, zname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
    1466               1 :                 if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
    1467               1 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" cannot be unlinked from within itself", fname);
    1468               1 :                         efree(arch);
    1469               1 :                         efree(entry);
    1470               1 :                         return;
    1471                 :                 }
    1472               0 :                 efree(arch);
    1473               0 :                 efree(entry);
    1474                 :         }
    1475                 : 
    1476               8 :         if (phar->is_persistent) {
    1477               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
    1478               0 :                 return;
    1479                 :         }
    1480                 : 
    1481               8 :         if (phar->refcount) {
    1482               1 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" has open file handles or objects.  fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname);
    1483               1 :                 return;
    1484                 :         }
    1485                 : 
    1486               7 :         fname = estrndup(phar->fname, phar->fname_len);
    1487                 : 
    1488                 :         /* invalidate phar cache */
    1489               7 :         PHAR_G(last_phar) = NULL;
    1490               7 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    1491                 : 
    1492               7 :         phar_archive_delref(phar TSRMLS_CC);
    1493               7 :         unlink(fname);
    1494               7 :         efree(fname);
    1495               7 :         RETURN_TRUE;
    1496                 : }
    1497                 : /* }}} */
    1498                 : 
    1499                 : #if HAVE_SPL
    1500                 : 
    1501                 : #define PHAR_ARCHIVE_OBJECT() \
    1502                 :         phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
    1503                 :         if (!phar_obj->arc.archive) { \
    1504                 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
    1505                 :                         "Cannot call method on an uninitialized Phar object"); \
    1506                 :                 return; \
    1507                 :         }
    1508                 : 
    1509                 : /* {{{ proto void Phar::__destruct()
    1510                 :  * if persistent, remove from the cache
    1511                 :  */
    1512                 : PHP_METHOD(Phar, __destruct)
    1513             430 : {
    1514             430 :         phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1515                 : 
    1516             430 :         if (phar_obj->arc.archive && phar_obj->arc.archive->is_persistent) {
    1517               0 :                 zend_hash_del(&PHAR_GLOBALS->phar_persist_map, (const char *) phar_obj->arc.archive, sizeof(phar_obj->arc.archive));
    1518                 :         }
    1519             430 : }
    1520                 : /* }}} */
    1521                 : 
    1522                 : struct _phar_t {
    1523                 :         phar_archive_object *p;
    1524                 :         zend_class_entry *c;
    1525                 :         char *b;
    1526                 :         uint l;
    1527                 :         zval *ret;
    1528                 :         int count;
    1529                 :         php_stream *fp;
    1530                 : };
    1531                 : 
    1532                 : static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
    1533            3147 : {
    1534                 :         zval **value;
    1535                 :         zend_uchar key_type;
    1536            3147 :         zend_bool close_fp = 1;
    1537                 :         ulong int_key;
    1538            3147 :         struct _phar_t *p_obj = (struct _phar_t*) puser;
    1539            3147 :         uint str_key_len, base_len = p_obj->l, fname_len;
    1540                 :         phar_entry_data *data;
    1541                 :         php_stream *fp;
    1542                 :         size_t contents_len;
    1543            3147 :         char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
    1544                 :         phar_zstr key;
    1545                 :         char *str_key;
    1546            3147 :         zend_class_entry *ce = p_obj->c;
    1547            3147 :         phar_archive_object *phar_obj = p_obj->p;
    1548            3147 :         char *str = "[stream]";
    1549                 : 
    1550            3147 :         iter->funcs->get_current_data(iter, &value TSRMLS_CC);
    1551                 : 
    1552            3147 :         if (EG(exception)) {
    1553               0 :                 return ZEND_HASH_APPLY_STOP;
    1554                 :         }
    1555                 : 
    1556            3147 :         if (!value) {
    1557                 :                 /* failure in get_current_data */
    1558               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned no value", ce->name);
    1559               0 :                 return ZEND_HASH_APPLY_STOP;
    1560                 :         }
    1561                 : 
    1562            3147 :         switch (Z_TYPE_PP(value)) {
    1563                 : #if PHP_VERSION_ID >= 60000
    1564                 :                 case IS_UNICODE:
    1565                 :                         zval_unicode_to_string(*(value) TSRMLS_CC);
    1566                 :                         /* break intentionally omitted */
    1567                 : #endif
    1568                 :                 case IS_STRING:
    1569                 :                         break;
    1570                 :                 case IS_RESOURCE:
    1571               3 :                         php_stream_from_zval_no_verify(fp, value);
    1572                 : 
    1573               3 :                         if (!fp) {
    1574               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returned an invalid stream handle", ce->name);
    1575               0 :                                 return ZEND_HASH_APPLY_STOP;
    1576                 :                         }
    1577                 : 
    1578               3 :                         if (iter->funcs->get_current_key) {
    1579               3 :                                 key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
    1580                 : 
    1581               3 :                                 if (EG(exception)) {
    1582               0 :                                         return ZEND_HASH_APPLY_STOP;
    1583                 :                                 }
    1584                 : 
    1585               3 :                                 if (key_type == HASH_KEY_IS_LONG) {
    1586               0 :                                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
    1587               0 :                                         return ZEND_HASH_APPLY_STOP;
    1588                 :                                 }
    1589                 : 
    1590               3 :                                 if (key_type > 9) { /* IS_UNICODE == 10 */
    1591                 : #if PHP_VERSION_ID < 60000
    1592                 : /* this can never happen, but fixes a compile warning */
    1593               0 :                                         spprintf(&str_key, 0, "%s", key);
    1594                 : #else
    1595                 :                                         spprintf(&str_key, 0, "%v", key);
    1596                 :                                         ezfree(key);
    1597                 : #endif
    1598                 :                                 } else {
    1599               3 :                                         PHAR_STR(key, str_key);
    1600                 :                                 }
    1601                 : 
    1602               3 :                                 save = str_key;
    1603                 : 
    1604               3 :                                 if (str_key[str_key_len - 1] == '\0') {
    1605               3 :                                         str_key_len--;
    1606                 :                                 }
    1607                 : 
    1608                 :                         } else {
    1609               0 :                                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
    1610               0 :                                 return ZEND_HASH_APPLY_STOP;
    1611                 :                         }
    1612                 : 
    1613               3 :                         close_fp = 0;
    1614               3 :                         opened = (char *) estrndup(str, sizeof("[stream]") + 1);
    1615               3 :                         goto after_open_fp;
    1616                 :                 case IS_OBJECT:
    1617             133 :                         if (instanceof_function(Z_OBJCE_PP(value), spl_ce_SplFileInfo TSRMLS_CC)) {
    1618             130 :                                 char *test = NULL;
    1619                 :                                 zval dummy;
    1620             130 :                                 spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(*value TSRMLS_CC);
    1621                 : 
    1622             130 :                                 if (!base_len) {
    1623               0 :                                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returns an SplFileInfo object, so base directory must be specified", ce->name);
    1624               0 :                                         return ZEND_HASH_APPLY_STOP;
    1625                 :                                 }
    1626                 : 
    1627             130 :                                 switch (intern->type) {
    1628                 :                                         case SPL_FS_DIR:
    1629                 : #if PHP_VERSION_ID >= 60000
    1630                 :                                                 test = spl_filesystem_object_get_path(intern, NULL, NULL TSRMLS_CC).s;
    1631                 : #elif PHP_VERSION_ID >= 50300
    1632              81 :                                                 test = spl_filesystem_object_get_path(intern, NULL TSRMLS_CC);
    1633                 : #else
    1634                 :                                                 test = intern->path;
    1635                 : #endif
    1636              81 :                                                 fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
    1637              81 :                                                 php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC);
    1638                 : 
    1639              81 :                                                 if (Z_BVAL(dummy)) {
    1640                 :                                                         /* ignore directories */
    1641               6 :                                                         efree(fname);
    1642               6 :                                                         return ZEND_HASH_APPLY_KEEP;
    1643                 :                                                 }
    1644                 : 
    1645              75 :                                                 test = expand_filepath(fname, NULL TSRMLS_CC);
    1646                 : 
    1647              75 :                                                 if (test) {
    1648              75 :                                                         efree(fname);
    1649              75 :                                                         fname = test;
    1650              75 :                                                         fname_len = strlen(fname);
    1651                 :                                                 }
    1652                 : 
    1653              75 :                                                 save = fname;
    1654              75 :                                                 goto phar_spl_fileinfo;
    1655                 :                                         case SPL_FS_INFO:
    1656                 :                                         case SPL_FS_FILE:
    1657                 : #if PHP_VERSION_ID >= 60000
    1658                 :                                                 if (intern->file_name_type == IS_UNICODE) {
    1659                 :                                                         zval zv;
    1660                 : 
    1661                 :                                                         INIT_ZVAL(zv);
    1662                 :                                                         Z_UNIVAL(zv) = intern->file_name;
    1663                 :                                                         Z_UNILEN(zv) = intern->file_name_len;
    1664                 :                                                         Z_TYPE(zv) = IS_UNICODE;
    1665                 : 
    1666                 :                                                         zval_copy_ctor(&zv);
    1667                 :                                                         zval_unicode_to_string(&zv TSRMLS_CC);
    1668                 :                                                         fname = expand_filepath(Z_STRVAL(zv), NULL TSRMLS_CC);
    1669                 :                                                         ezfree(Z_UNIVAL(zv));
    1670                 :                                                 } else {
    1671                 :                                                         fname = expand_filepath(intern->file_name.s, NULL TSRMLS_CC);
    1672                 :                                                 }
    1673                 : #else
    1674              49 :                                                 fname = expand_filepath(intern->file_name, NULL TSRMLS_CC);
    1675                 : #endif
    1676              49 :                                                 fname_len = strlen(fname);
    1677              49 :                                                 save = fname;
    1678              49 :                                                 goto phar_spl_fileinfo;
    1679                 :                                 }
    1680                 :                         }
    1681                 :                         /* fall-through */
    1682                 :                 default:
    1683               3 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid value (must return a string)", ce->name);
    1684               3 :                         return ZEND_HASH_APPLY_STOP;
    1685                 :         }
    1686                 : 
    1687            3011 :         fname = Z_STRVAL_PP(value);
    1688            3011 :         fname_len = Z_STRLEN_PP(value);
    1689                 : 
    1690            3135 : phar_spl_fileinfo:
    1691            3135 :         if (base_len) {
    1692             124 :                 temp = expand_filepath(base, NULL TSRMLS_CC);
    1693             124 :                 base = temp;
    1694             124 :                 base_len = strlen(base);
    1695                 : 
    1696             124 :                 if (strstr(fname, base)) {
    1697             124 :                         str_key_len = fname_len - base_len;
    1698                 : 
    1699             124 :                         if (str_key_len <= 0) {
    1700               0 :                                 if (save) {
    1701               0 :                                         efree(save);
    1702               0 :                                         efree(temp);
    1703                 :                                 }
    1704               0 :                                 return ZEND_HASH_APPLY_KEEP;
    1705                 :                         }
    1706                 : 
    1707             124 :                         str_key = fname + base_len;
    1708                 : 
    1709             124 :                         if (*str_key == '/' || *str_key == '\\') {
    1710              14 :                                 str_key++;
    1711              14 :                                 str_key_len--;
    1712                 :                         }
    1713                 : 
    1714                 :                 } else {
    1715               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that is not in the base directory \"%s\"", ce->name, fname, base);
    1716                 : 
    1717               0 :                         if (save) {
    1718               0 :                                 efree(save);
    1719               0 :                                 efree(temp);
    1720                 :                         }
    1721                 : 
    1722               0 :                         return ZEND_HASH_APPLY_STOP;
    1723                 :                 }
    1724                 :         } else {
    1725            3011 :                 if (iter->funcs->get_current_key) {
    1726            3011 :                         key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
    1727                 : 
    1728            3011 :                         if (EG(exception)) {
    1729               0 :                                 return ZEND_HASH_APPLY_STOP;
    1730                 :                         }
    1731                 : 
    1732            3011 :                         if (key_type == HASH_KEY_IS_LONG) {
    1733               3 :                                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
    1734               3 :                                 return ZEND_HASH_APPLY_STOP;
    1735                 :                         }
    1736                 : 
    1737            3008 :                         if (key_type > 9) { /* IS_UNICODE == 10 */
    1738                 : #if PHP_VERSION_ID < 60000
    1739                 : /* this can never happen, but fixes a compile warning */
    1740               0 :                                 spprintf(&str_key, 0, "%s", key);
    1741                 : #else
    1742                 :                                 spprintf(&str_key, 0, "%v", key);
    1743                 :                                 ezfree(key);
    1744                 : #endif
    1745                 :                         } else {
    1746            3008 :                                 PHAR_STR(key, str_key);
    1747                 :                         }
    1748                 : 
    1749            3008 :                         save = str_key;
    1750                 : 
    1751            3008 :                         if (str_key[str_key_len - 1] == '\0') str_key_len--;
    1752                 :                 } else {
    1753               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
    1754               0 :                         return ZEND_HASH_APPLY_STOP;
    1755                 :                 }
    1756                 :         }
    1757                 : #if PHP_MAJOR_VERSION < 6
    1758            3132 :         if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
    1759               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that safe mode prevents opening", ce->name, fname);
    1760                 : 
    1761               0 :                 if (save) {
    1762               0 :                         efree(save);
    1763                 :                 }
    1764                 : 
    1765               0 :                 if (temp) {
    1766               0 :                         efree(temp);
    1767                 :                 }
    1768                 : 
    1769               0 :                 return ZEND_HASH_APPLY_STOP;
    1770                 :         }
    1771                 : #endif
    1772                 : 
    1773            3132 :         if (php_check_open_basedir(fname TSRMLS_CC)) {
    1774               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that open_basedir prevents opening", ce->name, fname);
    1775                 : 
    1776               0 :                 if (save) {
    1777               0 :                         efree(save);
    1778                 :                 }
    1779                 : 
    1780               0 :                 if (temp) {
    1781               0 :                         efree(temp);
    1782                 :                 }
    1783                 : 
    1784               0 :                 return ZEND_HASH_APPLY_STOP;
    1785                 :         }
    1786                 : 
    1787                 :         /* try to open source file, then create internal phar file and copy contents */
    1788            3132 :         fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened);
    1789                 : 
    1790            3132 :         if (!fp) {
    1791               3 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a file that could not be opened \"%s\"", ce->name, fname);
    1792                 : 
    1793               3 :                 if (save) {
    1794               3 :                         efree(save);
    1795                 :                 }
    1796                 : 
    1797               3 :                 if (temp) {
    1798               0 :                         efree(temp);
    1799                 :                 }
    1800                 : 
    1801               3 :                 return ZEND_HASH_APPLY_STOP;
    1802                 :         }
    1803            3132 : after_open_fp:
    1804            3132 :         if (str_key_len >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
    1805                 :                 /* silently skip any files that would be added to the magic .phar directory */
    1806               3 :                 if (save) {
    1807               3 :                         efree(save);
    1808                 :                 }
    1809                 : 
    1810               3 :                 if (temp) {
    1811               0 :                         efree(temp);
    1812                 :                 }
    1813                 : 
    1814               3 :                 if (opened) {
    1815               3 :                         efree(opened);
    1816                 :                 }
    1817                 : 
    1818               3 :                 if (close_fp) {
    1819               3 :                         php_stream_close(fp);
    1820                 :                 }
    1821                 : 
    1822               3 :                 return ZEND_HASH_APPLY_KEEP;
    1823                 :         }
    1824                 : 
    1825            3129 :         if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error, 1 TSRMLS_CC))) {
    1826               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error);
    1827               0 :                 efree(error);
    1828                 : 
    1829               0 :                 if (save) {
    1830               0 :                         efree(save);
    1831                 :                 }
    1832                 : 
    1833               0 :                 if (opened) {
    1834               0 :                         efree(opened);
    1835                 :                 }
    1836                 : 
    1837               0 :                 if (temp) {
    1838               0 :                         efree(temp);
    1839                 :                 }
    1840                 : 
    1841               0 :                 if (close_fp) {
    1842               0 :                         php_stream_close(fp);
    1843                 :                 }
    1844                 : 
    1845               0 :                 return ZEND_HASH_APPLY_STOP;
    1846                 : 
    1847                 :         } else {
    1848            3129 :                 if (error) {
    1849               0 :                         efree(error);
    1850                 :                 }
    1851                 :                 /* convert to PHAR_UFP */
    1852            3129 :                 if (data->internal_file->fp_type == PHAR_MOD) {
    1853            3129 :                         php_stream_close(data->internal_file->fp);
    1854                 :                 }
    1855                 : 
    1856            3129 :                 data->internal_file->fp = NULL;
    1857            3129 :                 data->internal_file->fp_type = PHAR_UFP;
    1858            3129 :                 data->internal_file->offset_abs = data->internal_file->offset = php_stream_tell(p_obj->fp);
    1859            3129 :                 data->fp = NULL;
    1860            3129 :                 phar_stream_copy_to_stream(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len);
    1861            3129 :                 data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize =
    1862                 :                         php_stream_tell(p_obj->fp) - data->internal_file->offset;
    1863                 :         }
    1864                 : 
    1865            3129 :         if (close_fp) {
    1866            3126 :                 php_stream_close(fp);
    1867                 :         }
    1868                 : 
    1869            3129 :         add_assoc_string(p_obj->ret, str_key, opened, 0);
    1870                 : 
    1871            3129 :         if (save) {
    1872            3129 :                 efree(save);
    1873                 :         }
    1874                 : 
    1875            3129 :         if (temp) {
    1876             124 :                 efree(temp);
    1877                 :         }
    1878                 : 
    1879            3129 :         data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
    1880            3129 :         phar_entry_delref(data TSRMLS_CC);
    1881                 : 
    1882            3129 :         return ZEND_HASH_APPLY_KEEP;
    1883                 : }
    1884                 : /* }}} */
    1885                 : 
    1886                 : /* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex])
    1887                 :  * Construct a phar archive from an existing directory, recursively.
    1888                 :  * Optional second parameter is a regular expression for filtering directory contents.
    1889                 :  * 
    1890                 :  * Return value is an array mapping phar index to actual files added.
    1891                 :  */
    1892                 : PHP_METHOD(Phar, buildFromDirectory)
    1893               8 : {
    1894               8 :         char *dir, *error, *regex = NULL;
    1895               8 :         int dir_len, regex_len = 0;
    1896               8 :         zend_bool apply_reg = 0;
    1897               8 :         zval arg, arg2, *iter, *iteriter, *regexiter = NULL;
    1898                 :         struct _phar_t pass;
    1899                 : 
    1900               8 :         PHAR_ARCHIVE_OBJECT();
    1901                 : 
    1902               8 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    1903               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    1904                 :                         "Cannot write to archive - write operations restricted by INI setting");
    1905               1 :                 return;
    1906                 :         }
    1907                 : 
    1908               7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &dir, &dir_len, &regex, &regex_len) == FAILURE) {
    1909               1 :                 RETURN_FALSE;
    1910                 :         }
    1911                 : 
    1912               6 :         MAKE_STD_ZVAL(iter);
    1913                 : 
    1914               6 :         if (SUCCESS != object_init_ex(iter, spl_ce_RecursiveDirectoryIterator)) {
    1915               0 :                 zval_ptr_dtor(&iter);
    1916               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
    1917               0 :                 RETURN_FALSE;
    1918                 :         }
    1919                 : 
    1920               6 :         INIT_PZVAL(&arg);
    1921               6 :         ZVAL_STRINGL(&arg, dir, dir_len, 0);
    1922               6 :         INIT_PZVAL(&arg2);
    1923                 : #if PHP_VERSION_ID < 50300
    1924                 :         ZVAL_LONG(&arg2, 0);
    1925                 : #else
    1926               6 :         ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS);
    1927                 : #endif
    1928                 : 
    1929               6 :         zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator, 
    1930                 :                         &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2);
    1931                 : 
    1932               6 :         if (EG(exception)) {
    1933               1 :                 zval_ptr_dtor(&iter);
    1934               1 :                 RETURN_FALSE;
    1935                 :         }
    1936                 : 
    1937               5 :         MAKE_STD_ZVAL(iteriter);
    1938                 : 
    1939               5 :         if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) {
    1940               0 :                 zval_ptr_dtor(&iter);
    1941               0 :                 zval_ptr_dtor(&iteriter);
    1942               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
    1943               0 :                 RETURN_FALSE;
    1944                 :         }
    1945                 : 
    1946               5 :         zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator, 
    1947                 :                         &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter);
    1948                 : 
    1949               5 :         if (EG(exception)) {
    1950               0 :                 zval_ptr_dtor(&iter);
    1951               0 :                 zval_ptr_dtor(&iteriter);
    1952               0 :                 RETURN_FALSE;
    1953                 :         }
    1954                 : 
    1955               5 :         zval_ptr_dtor(&iter);
    1956                 : 
    1957               5 :         if (regex_len > 0) {
    1958               2 :                 apply_reg = 1;
    1959               2 :                 MAKE_STD_ZVAL(regexiter);
    1960                 : 
    1961               2 :                 if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) {
    1962               0 :                         zval_ptr_dtor(&iteriter);
    1963               0 :                         zval_dtor(regexiter);
    1964               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname);
    1965               0 :                         RETURN_FALSE;
    1966                 :                 }
    1967                 : 
    1968               2 :                 INIT_PZVAL(&arg2);
    1969               2 :                 ZVAL_STRINGL(&arg2, regex, regex_len, 0);
    1970                 : 
    1971               2 :                 zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator, 
    1972                 :                         &spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2);
    1973                 :         }
    1974                 : 
    1975               5 :         array_init(return_value);
    1976                 : 
    1977               5 :         pass.c = apply_reg ? Z_OBJCE_P(regexiter) : Z_OBJCE_P(iteriter);
    1978               5 :         pass.p = phar_obj;
    1979               5 :         pass.b = dir;
    1980               5 :         pass.l = dir_len;
    1981               5 :         pass.count = 0;
    1982               5 :         pass.ret = return_value;
    1983               5 :         pass.fp = php_stream_fopen_tmpfile();
    1984                 : 
    1985               5 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    1986               0 :                 zval_ptr_dtor(&iteriter);
    1987               0 :                 if (apply_reg) {
    1988               0 :                         zval_ptr_dtor(&regexiter);
    1989                 :                 }
    1990               0 :                 php_stream_close(pass.fp);
    1991               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    1992               0 :                 return;
    1993                 :         }
    1994                 : 
    1995               5 :         if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
    1996               5 :                 zval_ptr_dtor(&iteriter);
    1997                 : 
    1998               5 :                 if (apply_reg) {
    1999               2 :                         zval_ptr_dtor(&regexiter);
    2000                 :                 }
    2001                 : 
    2002               5 :                 phar_obj->arc.archive->ufp = pass.fp;
    2003               5 :                 phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    2004                 : 
    2005               5 :                 if (error) {
    2006               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2007               0 :                         efree(error);
    2008                 :                 }
    2009                 : 
    2010                 :         } else {
    2011               0 :                 zval_ptr_dtor(&iteriter);
    2012               0 :                 if (apply_reg) {
    2013               0 :                         zval_ptr_dtor(&regexiter);
    2014                 :                 }
    2015               0 :                 php_stream_close(pass.fp);
    2016                 :         }
    2017                 : }
    2018                 : /* }}} */
    2019                 : 
    2020                 : /* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory])
    2021                 :  * Construct a phar archive from an iterator.  The iterator must return a series of strings
    2022                 :  * that are full paths to files that should be added to the phar.  The iterator key should
    2023                 :  * be the path that the file will have within the phar archive.
    2024                 :  *
    2025                 :  * If base directory is specified, then the key will be ignored, and instead the portion of
    2026                 :  * the current value minus the base directory will be used
    2027                 :  *
    2028                 :  * Returned is an array mapping phar index to actual file added
    2029                 :  */
    2030                 : PHP_METHOD(Phar, buildFromIterator)
    2031              24 : {
    2032                 :         zval *obj;
    2033                 :         char *error;
    2034              24 :         uint base_len = 0;
    2035              24 :         char *base = NULL;
    2036                 :         struct _phar_t pass;
    2037                 : 
    2038              24 :         PHAR_ARCHIVE_OBJECT();
    2039                 : 
    2040              24 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    2041               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2042                 :                         "Cannot write out phar archive, phar is read-only");
    2043               1 :                 return;
    2044                 :         }
    2045                 : 
    2046              23 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &obj, zend_ce_traversable, &base, &base_len) == FAILURE) {
    2047               2 :                 RETURN_FALSE;
    2048                 :         }
    2049                 : 
    2050              21 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    2051               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    2052               0 :                 return;
    2053                 :         }
    2054                 : 
    2055              21 :         array_init(return_value);
    2056                 : 
    2057              21 :         pass.c = Z_OBJCE_P(obj);
    2058              21 :         pass.p = phar_obj;
    2059              21 :         pass.b = base;
    2060              21 :         pass.l = base_len;
    2061              21 :         pass.ret = return_value;
    2062              21 :         pass.count = 0;
    2063              21 :         pass.fp = php_stream_fopen_tmpfile();
    2064                 : 
    2065              21 :         if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
    2066              12 :                 phar_obj->arc.archive->ufp = pass.fp;
    2067              12 :                 phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    2068              12 :                 if (error) {
    2069               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2070               0 :                         efree(error);
    2071                 :                 }
    2072                 :         } else {
    2073               9 :                 php_stream_close(pass.fp);
    2074                 :         }
    2075                 : }
    2076                 : /* }}} */
    2077                 : 
    2078                 : /* {{{ proto int Phar::count()
    2079                 :  * Returns the number of entries in the Phar archive
    2080                 :  */
    2081                 : PHP_METHOD(Phar, count)
    2082               2 : {
    2083               2 :         PHAR_ARCHIVE_OBJECT();
    2084                 : 
    2085               2 :         RETURN_LONG(zend_hash_num_elements(&phar_obj->arc.archive->manifest));
    2086                 : }
    2087                 : /* }}} */
    2088                 : 
    2089                 : /* {{{ proto bool Phar::isFileFormat(int format)
    2090                 :  * Returns true if the phar archive is based on the tar/zip/phar file format depending
    2091                 :  * on whether Phar::TAR, Phar::ZIP or Phar::PHAR was passed in
    2092                 :  */
    2093                 : PHP_METHOD(Phar, isFileFormat)
    2094              97 : {
    2095                 :         long type;
    2096              97 :         PHAR_ARCHIVE_OBJECT();
    2097                 : 
    2098              97 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
    2099               1 :                 RETURN_FALSE;
    2100                 :         }
    2101                 : 
    2102              96 :         switch (type) {
    2103                 :                 case PHAR_FORMAT_TAR:
    2104              43 :                         RETURN_BOOL(phar_obj->arc.archive->is_tar);
    2105                 :                 case PHAR_FORMAT_ZIP:
    2106              28 :                         RETURN_BOOL(phar_obj->arc.archive->is_zip);
    2107                 :                 case PHAR_FORMAT_PHAR:
    2108              24 :                         RETURN_BOOL(!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip);
    2109                 :                 default:
    2110               1 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown file format specified");
    2111                 :         }
    2112                 : }
    2113                 : /* }}} */
    2114                 : 
    2115                 : static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */
    2116             167 : {
    2117                 :         char *error;
    2118                 :         off_t offset;
    2119                 :         phar_entry_info *link;
    2120                 : 
    2121             167 :         if (FAILURE == phar_open_entry_fp(entry, &error, 1 TSRMLS_CC)) {
    2122               0 :                 if (error) {
    2123               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2124                 :                                 "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error);
    2125               0 :                         efree(error);
    2126                 :                 } else {
    2127               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2128                 :                                 "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename);
    2129                 :                 }
    2130               0 :                 return FAILURE;
    2131                 :         }
    2132                 : 
    2133                 :         /* copy old contents in entirety */
    2134             167 :         phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
    2135             167 :         offset = php_stream_tell(fp);
    2136             167 :         link = phar_get_link_source(entry TSRMLS_CC);
    2137                 : 
    2138             167 :         if (!link) {
    2139               0 :                 link = entry;
    2140                 :         }
    2141                 : 
    2142             167 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
    2143               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2144                 :                         "Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
    2145               0 :                 return FAILURE;
    2146                 :         }
    2147                 : 
    2148             167 :         if (entry->fp_type == PHAR_MOD) {
    2149                 :                 /* save for potential restore on error */
    2150               0 :                 entry->cfp = entry->fp;
    2151               0 :                 entry->fp = NULL;
    2152                 :         }
    2153                 : 
    2154                 :         /* set new location of file contents */
    2155             167 :         entry->fp_type = PHAR_FP;
    2156             167 :         entry->offset = offset;
    2157             167 :         return SUCCESS;
    2158                 : }
    2159                 : /* }}} */
    2160                 : 
    2161                 : static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC) /* {{{ */
    2162              51 : {
    2163              51 :         char *oldname = NULL, *oldpath = NULL;
    2164              51 :         char *basename = NULL, *basepath = NULL;
    2165              51 :         char *newname = NULL, *newpath = NULL;
    2166                 :         zval *ret, arg1;
    2167                 :         zend_class_entry *ce;
    2168                 :         char *error;
    2169                 :         const char *pcr_error;
    2170              51 :         int ext_len = ext ? strlen(ext) : 0;
    2171                 :         int oldname_len;
    2172              51 :         phar_archive_data **pphar = NULL;
    2173                 :         php_stream_statbuf ssb;
    2174                 : 
    2175              51 :         if (!ext) {
    2176              36 :                 if (phar->is_zip) {
    2177                 : 
    2178               8 :                         if (phar->is_data) {
    2179               3 :                                 ext = "zip";
    2180                 :                         } else {
    2181               5 :                                 ext = "phar.zip";
    2182                 :                         }
    2183                 : 
    2184              28 :                 } else if (phar->is_tar) {
    2185                 : 
    2186              20 :                         switch (phar->flags) {
    2187                 :                                 case PHAR_FILE_COMPRESSED_GZ:
    2188               5 :                                         if (phar->is_data) {
    2189               1 :                                                 ext = "tar.gz";
    2190                 :                                         } else {
    2191               4 :                                                 ext = "phar.tar.gz";
    2192                 :                                         }
    2193               5 :                                         break;
    2194                 :                                 case PHAR_FILE_COMPRESSED_BZ2:
    2195               3 :                                         if (phar->is_data) {
    2196               1 :                                                 ext = "tar.bz2";
    2197                 :                                         } else {
    2198               2 :                                                 ext = "phar.tar.bz2";
    2199                 :                                         }
    2200               3 :                                         break;
    2201                 :                                 default:
    2202              12 :                                         if (phar->is_data) {
    2203               4 :                                                 ext = "tar";
    2204                 :                                         } else {
    2205               8 :                                                 ext = "phar.tar";
    2206                 :                                         }
    2207                 :                         }
    2208                 :                 } else {
    2209                 : 
    2210               8 :                         switch (phar->flags) {
    2211                 :                                 case PHAR_FILE_COMPRESSED_GZ:
    2212               3 :                                         ext = "phar.gz";
    2213               3 :                                         break;
    2214                 :                                 case PHAR_FILE_COMPRESSED_BZ2:
    2215               1 :                                         ext = "phar.bz2";
    2216               1 :                                         break;
    2217                 :                                 default:
    2218               4 :                                         ext = "phar";
    2219                 :                         }
    2220                 :                 }
    2221              15 :         } else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) {
    2222                 : 
    2223               0 :                 if (phar->is_data) {
    2224               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
    2225                 :                 } else {
    2226               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
    2227                 :                 }
    2228               0 :                 return NULL;
    2229                 :         }
    2230                 : 
    2231              51 :         if (ext[0] == '.') {
    2232              11 :                 ++ext;
    2233                 :         }
    2234                 : 
    2235              51 :         oldpath = estrndup(phar->fname, phar->fname_len);
    2236              51 :         oldname = zend_memrchr(phar->fname, '/', phar->fname_len);
    2237              51 :         ++oldname;
    2238              51 :         oldname_len = strlen(oldname);
    2239                 : 
    2240              51 :         basename = estrndup(oldname, oldname_len);
    2241              51 :         spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext);
    2242              51 :         efree(basename);
    2243                 : 
    2244                 :         
    2245                 : 
    2246              51 :         basepath = estrndup(oldpath, (strlen(oldpath) - oldname_len));
    2247              51 :         phar->fname_len = spprintf(&newpath, 0, "%s%s", basepath, newname);
    2248              51 :         phar->fname = newpath;
    2249              51 :         phar->ext = newpath + phar->fname_len - strlen(ext) - 1;
    2250              51 :         efree(basepath);
    2251              51 :         efree(newname);
    2252                 : 
    2253              51 :         if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, newpath, phar->fname_len, (void **) &pphar)) {
    2254               0 :                 efree(oldpath);
    2255               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
    2256               0 :                 return NULL;
    2257                 :         }
    2258                 : 
    2259              51 :         if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void **) &pphar)) {
    2260               1 :                 if ((*pphar)->fname_len == phar->fname_len && !memcmp((*pphar)->fname, phar->fname, phar->fname_len)) {
    2261               1 :                         if (!zend_hash_num_elements(&phar->manifest)) {
    2262               0 :                                 (*pphar)->is_tar = phar->is_tar;
    2263               0 :                                 (*pphar)->is_zip = phar->is_zip;
    2264               0 :                                 (*pphar)->is_data = phar->is_data;
    2265               0 :                                 (*pphar)->flags = phar->flags;
    2266               0 :                                 (*pphar)->fp = phar->fp;
    2267               0 :                                 phar->fp = NULL;
    2268               0 :                                 phar_destroy_phar_data(phar TSRMLS_CC);
    2269               0 :                                 phar = *pphar;
    2270               0 :                                 phar->refcount++;
    2271               0 :                                 newpath = oldpath;
    2272               0 :                                 goto its_ok;
    2273                 :                         }
    2274                 :                 }
    2275                 : 
    2276               1 :                 efree(oldpath);
    2277               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
    2278               1 :                 return NULL;
    2279                 :         }
    2280              50 : its_ok:
    2281              50 :         if (SUCCESS == php_stream_stat_path(newpath, &ssb)) {
    2282               1 :                 efree(oldpath);
    2283               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" exists and must be unlinked prior to conversion", newpath);
    2284               1 :                 return NULL;
    2285                 :         }
    2286              49 :         if (!phar->is_data) {
    2287              35 :                 if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) {
    2288               1 :                         efree(oldpath);
    2289               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext);
    2290               1 :                         return NULL;
    2291                 :                 }
    2292                 : 
    2293              34 :                 if (phar->alias) {
    2294              22 :                         if (phar->is_temporary_alias) {
    2295              15 :                                 phar->alias = NULL;
    2296              15 :                                 phar->alias_len = 0;
    2297                 :                         } else {
    2298               7 :                                 phar->alias = estrndup(newpath, strlen(newpath));
    2299               7 :                                 phar->alias_len = strlen(newpath);
    2300               7 :                                 phar->is_temporary_alias = 1;
    2301               7 :                                 zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL);
    2302                 :                         }
    2303                 :                 }
    2304                 : 
    2305                 :         } else {
    2306                 : 
    2307              14 :                 if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) {
    2308               3 :                         efree(oldpath);
    2309               3 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
    2310               3 :                         return NULL;
    2311                 :                 }
    2312                 : 
    2313              11 :                 phar->alias = NULL;
    2314              11 :                 phar->alias_len = 0;
    2315                 :         }
    2316                 : 
    2317              45 :         if ((!pphar || phar == *pphar) && SUCCESS != zend_hash_update(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL)) {
    2318               0 :                 efree(oldpath);
    2319               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname);
    2320               0 :                 return NULL;
    2321                 :         }
    2322                 : 
    2323              45 :         phar_flush(phar, 0, 0, 1, &error TSRMLS_CC);
    2324                 : 
    2325              45 :         if (error) {
    2326               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
    2327               0 :                 efree(error);
    2328               0 :                 efree(oldpath);
    2329               0 :                 return NULL;
    2330                 :         }
    2331                 : 
    2332              45 :         efree(oldpath);
    2333                 : 
    2334              45 :         if (phar->is_data) {
    2335              11 :                 ce = phar_ce_data;
    2336                 :         } else {
    2337              34 :                 ce = phar_ce_archive;
    2338                 :         }
    2339                 : 
    2340              45 :         MAKE_STD_ZVAL(ret);
    2341                 : 
    2342              45 :         if (SUCCESS != object_init_ex(ret, ce)) {
    2343               0 :                 zval_dtor(ret);
    2344               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname);
    2345               0 :                 return NULL;
    2346                 :         }
    2347                 : 
    2348              45 :         INIT_PZVAL(&arg1);
    2349              45 :         ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len, 0);
    2350                 : 
    2351              45 :         zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1);
    2352              45 :         return ret;
    2353                 : }
    2354                 : /* }}} */
    2355                 : 
    2356                 : static zval *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, php_uint32 flags TSRMLS_DC) /* {{{ */
    2357              51 : {
    2358                 :         phar_archive_data *phar;
    2359                 :         phar_entry_info *entry, newentry;
    2360                 :         zval *ret;
    2361                 : 
    2362                 :         /* invalidate phar cache */
    2363              51 :         PHAR_G(last_phar) = NULL;
    2364              51 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2365                 : 
    2366              51 :         phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
    2367                 :         /* set whole-archive compression and type from parameter */
    2368              51 :         phar->flags = flags;
    2369              51 :         phar->is_data = source->is_data;
    2370                 : 
    2371              51 :         switch (convert) {
    2372                 :                 case PHAR_FORMAT_TAR:
    2373              26 :                         phar->is_tar = 1;
    2374              26 :                         break;
    2375                 :                 case PHAR_FORMAT_ZIP:
    2376              13 :                         phar->is_zip = 1;
    2377              13 :                         break;
    2378                 :                 default:
    2379              12 :                         phar->is_data = 0;
    2380                 :                         break;
    2381                 :         }
    2382                 : 
    2383              51 :         zend_hash_init(&(phar->manifest), sizeof(phar_entry_info),
    2384                 :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    2385              51 :         zend_hash_init(&phar->mounted_dirs, sizeof(char *),
    2386                 :                 zend_get_hash_value, NULL, 0);
    2387              51 :         zend_hash_init(&phar->virtual_dirs, sizeof(char *),
    2388                 :                 zend_get_hash_value, NULL, 0);
    2389                 : 
    2390              51 :         phar->fp = php_stream_fopen_tmpfile();
    2391              51 :         phar->fname = source->fname;
    2392              51 :         phar->fname_len = source->fname_len;
    2393              51 :         phar->is_temporary_alias = source->is_temporary_alias;
    2394              51 :         phar->alias = source->alias;
    2395                 : 
    2396              51 :         if (source->metadata) {
    2397                 :                 zval *t;
    2398                 : 
    2399               2 :                 t = source->metadata;
    2400               2 :                 ALLOC_ZVAL(phar->metadata);
    2401               2 :                 *phar->metadata = *t;
    2402               2 :                 zval_copy_ctor(phar->metadata);
    2403                 : #if PHP_VERSION_ID < 50300
    2404                 :                 phar->metadata->refcount = 1;
    2405                 : #else
    2406               2 :                 Z_SET_REFCOUNT_P(phar->metadata, 1);
    2407                 : #endif
    2408                 : 
    2409               2 :                 phar->metadata_len = 0;
    2410                 :         }
    2411                 : 
    2412                 :         /* first copy each file's uncompressed contents to a temporary file and set per-file flags */
    2413             222 :         for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) {
    2414                 : 
    2415             171 :                 if (FAILURE == zend_hash_get_current_data(&source->manifest, (void **) &entry)) {
    2416               0 :                         zend_hash_destroy(&(phar->manifest));
    2417               0 :                         php_stream_close(phar->fp);
    2418               0 :                         efree(phar);
    2419               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2420                 :                                 "Cannot convert phar archive \"%s\"", source->fname);
    2421               0 :                         return NULL;
    2422                 :                 }
    2423                 : 
    2424             171 :                 newentry = *entry;
    2425                 : 
    2426             171 :                 if (newentry.link) {
    2427               2 :                         newentry.link = estrdup(newentry.link);
    2428               2 :                         goto no_copy;
    2429                 :                 }
    2430                 : 
    2431             169 :                 if (newentry.tmp) {
    2432               2 :                         newentry.tmp = estrdup(newentry.tmp);
    2433               2 :                         goto no_copy;
    2434                 :                 }
    2435                 : 
    2436             167 :                 newentry.metadata_str.c = 0;
    2437                 : 
    2438             167 :                 if (FAILURE == phar_copy_file_contents(&newentry, phar->fp TSRMLS_CC)) {
    2439               0 :                         zend_hash_destroy(&(phar->manifest));
    2440               0 :                         php_stream_close(phar->fp);
    2441               0 :                         efree(phar);
    2442                 :                         /* exception already thrown */
    2443               0 :                         return NULL;
    2444                 :                 }
    2445             171 : no_copy:
    2446             171 :                 newentry.filename = estrndup(newentry.filename, newentry.filename_len);
    2447                 : 
    2448             171 :                 if (newentry.metadata) {
    2449                 :                         zval *t;
    2450                 : 
    2451               8 :                         t = newentry.metadata;
    2452               8 :                         ALLOC_ZVAL(newentry.metadata);
    2453               8 :                         *newentry.metadata = *t;
    2454               8 :                         zval_copy_ctor(newentry.metadata);
    2455                 : #if PHP_VERSION_ID < 50300
    2456                 :                         newentry.metadata->refcount = 1;
    2457                 : #else
    2458               8 :                         Z_SET_REFCOUNT_P(newentry.metadata, 1);
    2459                 : #endif
    2460                 : 
    2461               8 :                         newentry.metadata_str.c = NULL;
    2462               8 :                         newentry.metadata_str.len = 0;
    2463                 :                 }
    2464                 : 
    2465             171 :                 newentry.is_zip = phar->is_zip;
    2466             171 :                 newentry.is_tar = phar->is_tar;
    2467                 : 
    2468             171 :                 if (newentry.is_tar) {
    2469              96 :                         newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE);
    2470                 :                 }
    2471                 : 
    2472             171 :                 newentry.is_modified = 1;
    2473             171 :                 newentry.phar = phar;
    2474             171 :                 newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
    2475             171 :                 phar_set_inode(&newentry TSRMLS_CC);
    2476             171 :                 zend_hash_add(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
    2477             171 :                 phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len TSRMLS_CC);
    2478                 :         }
    2479                 : 
    2480              51 :         if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) {
    2481              45 :                 return ret;
    2482                 :         } else {
    2483               6 :                 zend_hash_destroy(&(phar->manifest));
    2484               6 :                 zend_hash_destroy(&(phar->mounted_dirs));
    2485               6 :                 zend_hash_destroy(&(phar->virtual_dirs));
    2486               6 :                 php_stream_close(phar->fp);
    2487               6 :                 efree(phar->fname);
    2488               6 :                 efree(phar);
    2489               6 :                 return NULL;
    2490                 :         }
    2491                 : }
    2492                 : /* }}} */
    2493                 : 
    2494                 : /* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]])
    2495                 :  * Convert a phar.tar or phar.zip archive to the phar file format. The
    2496                 :  * optional parameter allows the user to determine the new
    2497                 :  * filename extension (default is phar).
    2498                 :  */
    2499                 : PHP_METHOD(Phar, convertToExecutable)
    2500              37 : {
    2501              37 :         char *ext = NULL;
    2502              37 :         int is_data, ext_len = 0;
    2503                 :         php_uint32 flags;
    2504                 :         zval *ret;
    2505                 :         /* a number that is not 0, 1 or 2 (Which is also Greg's birthday, so there) */
    2506              37 :         long format = 9021976, method = 9021976;
    2507              37 :         PHAR_ARCHIVE_OBJECT();
    2508                 : 
    2509              37 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
    2510               1 :                 return;
    2511                 :         }
    2512                 : 
    2513              36 :         if (PHAR_G(readonly)) {
    2514               2 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2515                 :                         "Cannot write out executable phar archive, phar is read-only");
    2516               2 :                 return;
    2517                 :         }
    2518                 : 
    2519              34 :         switch (format) {
    2520                 :                 case 9021976:
    2521                 :                 case PHAR_FORMAT_SAME: /* null is converted to 0 */
    2522                 :                         /* by default, use the existing format */
    2523               2 :                         if (phar_obj->arc.archive->is_tar) {
    2524               2 :                                 format = PHAR_FORMAT_TAR;
    2525               0 :                         } else if (phar_obj->arc.archive->is_zip) {
    2526               0 :                                 format = PHAR_FORMAT_ZIP;
    2527                 :                         } else {
    2528               0 :                                 format = PHAR_FORMAT_PHAR;
    2529                 :                         }
    2530               2 :                         break;
    2531                 :                 case PHAR_FORMAT_PHAR:
    2532                 :                 case PHAR_FORMAT_TAR:
    2533                 :                 case PHAR_FORMAT_ZIP:
    2534              31 :                         break;
    2535                 :                 default:
    2536               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2537                 :                                 "Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP");
    2538               1 :                         return;
    2539                 :         }
    2540                 : 
    2541              33 :         switch (method) {
    2542                 :                 case 9021976:
    2543              14 :                         flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
    2544              14 :                         break;
    2545                 :                 case 0:
    2546               9 :                         flags = PHAR_FILE_COMPRESSED_NONE;
    2547               9 :                         break;
    2548                 :                 case PHAR_ENT_COMPRESSED_GZ:
    2549               6 :                         if (format == PHAR_FORMAT_ZIP) {
    2550               1 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2551                 :                                         "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
    2552               1 :                                 return;
    2553                 :                         }
    2554                 : 
    2555               5 :                         if (!PHAR_G(has_zlib)) {
    2556               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2557                 :                                         "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
    2558               0 :                                 return;
    2559                 :                         }
    2560                 : 
    2561               5 :                         flags = PHAR_FILE_COMPRESSED_GZ;
    2562               5 :                         break;
    2563                 :                 case PHAR_ENT_COMPRESSED_BZ2:
    2564               3 :                         if (format == PHAR_FORMAT_ZIP) {
    2565               1 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2566                 :                                         "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
    2567               1 :                                 return;
    2568                 :                         }
    2569                 : 
    2570               2 :                         if (!PHAR_G(has_bz2)) {
    2571               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2572                 :                                         "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
    2573               0 :                                 return;
    2574                 :                         }
    2575                 : 
    2576               2 :                         flags = PHAR_FILE_COMPRESSED_BZ2;
    2577               2 :                         break;
    2578                 :                 default:
    2579               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2580                 :                                 "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
    2581               1 :                         return;
    2582                 :         }
    2583                 : 
    2584              30 :         is_data = phar_obj->arc.archive->is_data;
    2585              30 :         phar_obj->arc.archive->is_data = 0;
    2586              30 :         ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
    2587              30 :         phar_obj->arc.archive->is_data = is_data;
    2588                 : 
    2589              30 :         if (ret) {
    2590              28 :                 RETURN_ZVAL(ret, 1, 1);
    2591                 :         } else {
    2592               2 :                 RETURN_NULL();
    2593                 :         }
    2594                 : }
    2595                 : /* }}} */
    2596                 : 
    2597                 : /* {{{ proto object Phar::convertToData([int format[, int compression [, string file_ext]]])
    2598                 :  * Convert an archive to a non-executable .tar or .zip.
    2599                 :  * The optional parameter allows the user to determine the new
    2600                 :  * filename extension (default is .zip or .tar).
    2601                 :  */
    2602                 : PHP_METHOD(Phar, convertToData)
    2603              22 : {
    2604              22 :         char *ext = NULL;
    2605              22 :         int is_data, ext_len = 0;
    2606                 :         php_uint32 flags;
    2607                 :         zval *ret;
    2608                 :         /* a number that is not 0, 1 or 2 (Which is also Greg's birthday so there) */
    2609              22 :         long format = 9021976, method = 9021976;
    2610              22 :         PHAR_ARCHIVE_OBJECT();
    2611                 : 
    2612              22 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
    2613               1 :                 return;
    2614                 :         }
    2615                 : 
    2616              21 :         switch (format) {
    2617                 :                 case 9021976:
    2618                 :                 case PHAR_FORMAT_SAME: /* null is converted to 0 */
    2619                 :                         /* by default, use the existing format */
    2620               3 :                         if (phar_obj->arc.archive->is_tar) {
    2621               1 :                                 format = PHAR_FORMAT_TAR;
    2622               2 :                         } else if (phar_obj->arc.archive->is_zip) {
    2623               1 :                                 format = PHAR_FORMAT_ZIP;
    2624                 :                         } else {
    2625               1 :                                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2626                 :                                         "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
    2627               1 :                                 return;
    2628                 :                         }
    2629               2 :                         break;
    2630                 :                 case PHAR_FORMAT_PHAR:
    2631               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2632                 :                                 "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
    2633               1 :                         return;
    2634                 :                 case PHAR_FORMAT_TAR:
    2635                 :                 case PHAR_FORMAT_ZIP:
    2636              16 :                         break;
    2637                 :                 default:
    2638               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2639                 :                                 "Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP");
    2640               1 :                         return;
    2641                 :         }
    2642                 : 
    2643              18 :         switch (method) {
    2644                 :                 case 9021976:
    2645               7 :                         flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
    2646               7 :                         break;
    2647                 :                 case 0:
    2648               3 :                         flags = PHAR_FILE_COMPRESSED_NONE;
    2649               3 :                         break;
    2650                 :                 case PHAR_ENT_COMPRESSED_GZ:
    2651               5 :                         if (format == PHAR_FORMAT_ZIP) {
    2652               1 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2653                 :                                         "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
    2654               1 :                                 return;
    2655                 :                         }
    2656                 : 
    2657               4 :                         if (!PHAR_G(has_zlib)) {
    2658               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2659                 :                                         "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
    2660               0 :                                 return;
    2661                 :                         }
    2662                 : 
    2663               4 :                         flags = PHAR_FILE_COMPRESSED_GZ;
    2664               4 :                         break;
    2665                 :                 case PHAR_ENT_COMPRESSED_BZ2:
    2666               2 :                         if (format == PHAR_FORMAT_ZIP) {
    2667               1 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2668                 :                                         "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
    2669               1 :                                 return;
    2670                 :                         }
    2671                 : 
    2672               1 :                         if (!PHAR_G(has_bz2)) {
    2673               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2674                 :                                         "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
    2675               0 :                                 return;
    2676                 :                         }
    2677                 : 
    2678               1 :                         flags = PHAR_FILE_COMPRESSED_BZ2;
    2679               1 :                         break;
    2680                 :                 default:
    2681               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    2682                 :                                 "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
    2683               1 :                         return;
    2684                 :         }
    2685                 : 
    2686              15 :         is_data = phar_obj->arc.archive->is_data;
    2687              15 :         phar_obj->arc.archive->is_data = 1;
    2688              15 :         ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
    2689              15 :         phar_obj->arc.archive->is_data = is_data;
    2690                 : 
    2691              15 :         if (ret) {
    2692              11 :                 RETURN_ZVAL(ret, 1, 1);
    2693                 :         } else {
    2694               4 :                 RETURN_NULL();
    2695                 :         }
    2696                 : }
    2697                 : /* }}} */
    2698                 : 
    2699                 : /* {{{ proto int|false Phar::isCompressed()
    2700                 :  * Returns Phar::GZ or PHAR::BZ2 if the entire archive is compressed
    2701                 :  * (.tar.gz/tar.bz2 and so on), or FALSE otherwise.
    2702                 :  */
    2703                 : PHP_METHOD(Phar, isCompressed)
    2704              19 : {
    2705              19 :         PHAR_ARCHIVE_OBJECT();
    2706                 : 
    2707              19 :         if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_GZ) {
    2708              10 :                 RETURN_LONG(PHAR_ENT_COMPRESSED_GZ);
    2709                 :         }
    2710                 : 
    2711               9 :         if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_BZ2) {
    2712               7 :                 RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2);
    2713                 :         }
    2714                 : 
    2715               2 :         RETURN_FALSE;
    2716                 : }
    2717                 : /* }}} */
    2718                 : 
    2719                 : /* {{{ proto bool Phar::isWritable()
    2720                 :  * Returns true if phar.readonly=0 or phar is a PharData AND the actual file is writable.
    2721                 :  */
    2722                 : PHP_METHOD(Phar, isWritable)
    2723               8 : {
    2724                 :         php_stream_statbuf ssb;
    2725               8 :         PHAR_ARCHIVE_OBJECT();
    2726                 : 
    2727               8 :         if (!phar_obj->arc.archive->is_writeable) {
    2728               3 :                 RETURN_FALSE;
    2729                 :         }
    2730                 : 
    2731               5 :         if (SUCCESS != php_stream_stat_path(phar_obj->arc.archive->fname, &ssb)) {
    2732               1 :                 if (phar_obj->arc.archive->is_brandnew) {
    2733                 :                         /* assume it works if the file doesn't exist yet */
    2734               1 :                         RETURN_TRUE;
    2735                 :                 }
    2736               0 :                 RETURN_FALSE;
    2737                 :         }
    2738                 : 
    2739               4 :         RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0);
    2740                 : }
    2741                 : /* }}} */
    2742                 : 
    2743                 : /* {{{ proto bool Phar::delete(string entry)
    2744                 :  * Deletes a named file within the archive.
    2745                 :  */
    2746                 : PHP_METHOD(Phar, delete)
    2747               7 : {
    2748                 :         char *fname;
    2749                 :         int fname_len;
    2750                 :         char *error;
    2751                 :         phar_entry_info *entry;
    2752               7 :         PHAR_ARCHIVE_OBJECT();
    2753                 : 
    2754               7 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    2755               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2756                 :                         "Cannot write out phar archive, phar is read-only");
    2757               1 :                 return;
    2758                 :         }
    2759                 : 
    2760               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    2761               1 :                 RETURN_FALSE;
    2762                 :         }
    2763                 : 
    2764               5 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    2765               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    2766               0 :                 return;
    2767                 :         }
    2768               5 :         if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
    2769               4 :                 if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
    2770               4 :                         if (entry->is_deleted) {
    2771                 :                                 /* entry is deleted, but has not been flushed to disk yet */
    2772               0 :                                 RETURN_TRUE;
    2773                 :                         } else {
    2774               4 :                                 entry->is_deleted = 1;
    2775               4 :                                 entry->is_modified = 1;
    2776               4 :                                 phar_obj->arc.archive->is_modified = 1;
    2777                 :                         }
    2778                 :                 }
    2779                 :         } else {
    2780               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be deleted", fname);
    2781               1 :                 RETURN_FALSE;
    2782                 :         }
    2783                 : 
    2784               4 :         phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
    2785               4 :         if (error) {
    2786               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2787               0 :                 efree(error);
    2788                 :         }
    2789                 : 
    2790               4 :         RETURN_TRUE;
    2791                 : }
    2792                 : /* }}} */
    2793                 : 
    2794                 : /* {{{ proto int Phar::getAlias()
    2795                 :  * Returns the alias for the Phar or NULL.
    2796                 :  */
    2797                 : PHP_METHOD(Phar, getAlias)
    2798              42 : {
    2799              42 :         PHAR_ARCHIVE_OBJECT();
    2800                 : 
    2801              42 :         if (phar_obj->arc.archive->alias && phar_obj->arc.archive->alias != phar_obj->arc.archive->fname) {
    2802              33 :                 RETURN_STRINGL(phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, 1);
    2803                 :         }
    2804                 : }
    2805                 : /* }}} */
    2806                 : 
    2807                 : /* {{{ proto int Phar::getPath()
    2808                 :  * Returns the real path to the phar archive on disk
    2809                 :  */
    2810                 : PHP_METHOD(Phar, getPath)
    2811              15 : {
    2812              15 :         PHAR_ARCHIVE_OBJECT();
    2813                 : 
    2814              15 :         RETURN_STRINGL(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, 1);
    2815                 : }
    2816                 : /* }}} */
    2817                 : 
    2818                 : /* {{{ proto bool Phar::setAlias(string alias)
    2819                 :  * Sets the alias for a Phar archive. The default value is the full path
    2820                 :  * to the archive.
    2821                 :  */
    2822                 : PHP_METHOD(Phar, setAlias)
    2823              53 : {
    2824                 :         char *alias, *error, *oldalias;
    2825                 :         phar_archive_data **fd_ptr;
    2826              53 :         int alias_len, oldalias_len, old_temp, readd = 0;
    2827                 : 
    2828              53 :         PHAR_ARCHIVE_OBJECT();
    2829                 : 
    2830              53 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    2831               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2832                 :                         "Cannot write out phar archive, phar is read-only");
    2833               1 :                 RETURN_FALSE;
    2834                 :         }
    2835                 : 
    2836                 :         /* invalidate phar cache */
    2837              52 :         PHAR_G(last_phar) = NULL;
    2838              52 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2839                 : 
    2840              52 :         if (phar_obj->arc.archive->is_data) {
    2841               3 :                 if (phar_obj->arc.archive->is_tar) {
    2842               2 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2843                 :                                 "A Phar alias cannot be set in a plain tar archive");
    2844                 :                 } else {
    2845               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2846                 :                                 "A Phar alias cannot be set in a plain zip archive");
    2847                 :                 }
    2848               3 :                 RETURN_FALSE;
    2849                 :         }
    2850                 : 
    2851              49 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &alias, &alias_len) == SUCCESS) {
    2852              48 :                 if (alias_len == phar_obj->arc.archive->alias_len && memcmp(phar_obj->arc.archive->alias, alias, alias_len) == 0) {
    2853               0 :                         RETURN_TRUE;
    2854                 :                 }
    2855              48 :                 if (alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
    2856               4 :                         spprintf(&error, 0, "alias \"%s\" is already used for archive \"%s\" and cannot be used for other archives", alias, (*fd_ptr)->fname);
    2857               4 :                         if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
    2858               1 :                                 efree(error);
    2859               1 :                                 goto valid_alias;
    2860                 :                         }
    2861               3 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2862               3 :                         efree(error);
    2863               3 :                         RETURN_FALSE;
    2864                 :                 }
    2865              44 :                 if (!phar_validate_alias(alias, alias_len)) {
    2866               4 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2867                 :                                 "Invalid alias \"%s\" specified for phar \"%s\"", alias, phar_obj->arc.archive->fname);
    2868               4 :                         RETURN_FALSE;
    2869                 :                 }
    2870              41 : valid_alias:
    2871              41 :                 if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    2872               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    2873               0 :                         return;
    2874                 :                 }
    2875              41 :                 if (phar_obj->arc.archive->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, (void**)&fd_ptr)) {
    2876              23 :                         zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len);
    2877              23 :                         readd = 1;
    2878                 :                 }
    2879                 : 
    2880              41 :                 oldalias = phar_obj->arc.archive->alias;
    2881              41 :                 oldalias_len = phar_obj->arc.archive->alias_len;
    2882              41 :                 old_temp = phar_obj->arc.archive->is_temporary_alias;
    2883                 : 
    2884              41 :                 if (alias_len) {
    2885              41 :                         phar_obj->arc.archive->alias = estrndup(alias, alias_len);
    2886                 :                 } else {
    2887               0 :                         phar_obj->arc.archive->alias = NULL;
    2888                 :                 }
    2889                 : 
    2890              41 :                 phar_obj->arc.archive->alias_len = alias_len;
    2891              41 :                 phar_obj->arc.archive->is_temporary_alias = 0;
    2892              41 :                 phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
    2893                 : 
    2894              41 :                 if (error) {
    2895               0 :                         phar_obj->arc.archive->alias = oldalias;
    2896               0 :                         phar_obj->arc.archive->alias_len = oldalias_len;
    2897               0 :                         phar_obj->arc.archive->is_temporary_alias = old_temp;
    2898               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2899               0 :                         if (readd) {
    2900               0 :                                 zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), oldalias, oldalias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
    2901                 :                         }
    2902               0 :                         efree(error);
    2903               0 :                         RETURN_FALSE;
    2904                 :                 }
    2905                 : 
    2906              41 :                 zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
    2907                 : 
    2908              41 :                 if (oldalias) {
    2909              41 :                         efree(oldalias);
    2910                 :                 }
    2911                 : 
    2912              41 :                 RETURN_TRUE;
    2913                 :         }
    2914                 : 
    2915               1 :         RETURN_FALSE;
    2916                 : }
    2917                 : /* }}} */
    2918                 : 
    2919                 : /* {{{ proto string Phar::getVersion()
    2920                 :  * Return version info of Phar archive
    2921                 :  */
    2922                 : PHP_METHOD(Phar, getVersion)
    2923               2 : {
    2924               2 :         PHAR_ARCHIVE_OBJECT();
    2925                 : 
    2926               1 :         RETURN_STRING(phar_obj->arc.archive->version, 1);
    2927                 : }
    2928                 : /* }}} */
    2929                 : 
    2930                 : /* {{{ proto void Phar::startBuffering()
    2931                 :  * Do not flush a writeable phar (save its contents) until explicitly requested
    2932                 :  */
    2933                 : PHP_METHOD(Phar, startBuffering)
    2934               9 : {
    2935               9 :         PHAR_ARCHIVE_OBJECT();
    2936                 : 
    2937               9 :         phar_obj->arc.archive->donotflush = 1;
    2938                 : }
    2939                 : /* }}} */
    2940                 : 
    2941                 : /* {{{ proto bool Phar::isBuffering()
    2942                 :  * Returns whether write operations are flushing to disk immediately.
    2943                 :  */
    2944                 : PHP_METHOD(Phar, isBuffering)
    2945               9 : {
    2946               9 :         PHAR_ARCHIVE_OBJECT();
    2947                 : 
    2948               9 :         RETURN_BOOL(phar_obj->arc.archive->donotflush);
    2949                 : }
    2950                 : /* }}} */
    2951                 : 
    2952                 : /* {{{ proto bool Phar::stopBuffering()
    2953                 :  * Saves the contents of a modified archive to disk.
    2954                 :  */
    2955                 : PHP_METHOD(Phar, stopBuffering)
    2956              69 : {
    2957                 :         char *error;
    2958                 : 
    2959              69 :         PHAR_ARCHIVE_OBJECT();
    2960                 : 
    2961              69 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    2962               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2963                 :                         "Cannot write out phar archive, phar is read-only");
    2964               0 :                 return;
    2965                 :         }
    2966                 : 
    2967              69 :         phar_obj->arc.archive->donotflush = 0;
    2968              69 :         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    2969                 : 
    2970              69 :         if (error) {
    2971               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    2972               0 :                 efree(error);
    2973                 :         }
    2974                 : }
    2975                 : /* }}} */
    2976                 : 
    2977                 : /* {{{ proto bool Phar::setStub(string|stream stub [, int len])
    2978                 :  * Change the stub in a phar, phar.tar or phar.zip archive to something other
    2979                 :  * than the default. The stub *must* end with a call to __HALT_COMPILER().
    2980                 :  */
    2981                 : PHP_METHOD(Phar, setStub)
    2982              83 : {
    2983                 :         zval *zstub;
    2984                 :         char *stub, *error;
    2985                 :         int stub_len;
    2986              83 :         long len = -1;
    2987                 :         php_stream *stream;
    2988              83 :         PHAR_ARCHIVE_OBJECT();
    2989                 : 
    2990              83 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    2991               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2992                 :                         "Cannot change stub, phar is read-only");
    2993               1 :                 return;
    2994                 :         }
    2995                 : 
    2996              82 :         if (phar_obj->arc.archive->is_data) {
    2997               3 :                 if (phar_obj->arc.archive->is_tar) {
    2998               2 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    2999                 :                                 "A Phar stub cannot be set in a plain tar archive");
    3000                 :                 } else {
    3001               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3002                 :                                 "A Phar stub cannot be set in a plain zip archive");
    3003                 :                 }
    3004               3 :                 return;
    3005                 :         }
    3006                 : 
    3007              79 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zstub, &len) == SUCCESS) {
    3008              10 :                 if ((php_stream_from_zval_no_verify(stream, &zstub)) != NULL) {
    3009              10 :                         if (len > 0) {
    3010               4 :                                 len = -len;
    3011                 :                         } else {
    3012               6 :                                 len = -1;
    3013                 :                         }
    3014              10 :                         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3015               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3016               0 :                                 return;
    3017                 :                         }
    3018              10 :                         phar_flush(phar_obj->arc.archive, (char *) &zstub, len, 0, &error TSRMLS_CC);
    3019              10 :                         if (error) {
    3020               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3021               0 :                                 efree(error);
    3022                 :                         }
    3023              10 :                         RETURN_TRUE;
    3024                 :                 } else {
    3025               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3026                 :                                 "Cannot change stub, unable to read from input stream");
    3027                 :                 }
    3028              69 :         } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) {
    3029              68 :                 if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3030               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3031               0 :                         return;
    3032                 :                 }
    3033              68 :                 phar_flush(phar_obj->arc.archive, stub, stub_len, 0, &error TSRMLS_CC);
    3034                 : 
    3035              68 :                 if (error) {
    3036               3 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3037               3 :                         efree(error);
    3038                 :                 }
    3039                 : 
    3040              68 :                 RETURN_TRUE;
    3041                 :         }
    3042                 : 
    3043               1 :         RETURN_FALSE;
    3044                 : }
    3045                 : /* }}} */
    3046                 : 
    3047                 : /* {{{ proto bool Phar::setDefaultStub([string index[, string webindex]])
    3048                 :  * In a pure phar archive, sets a stub that can be used to run the archive
    3049                 :  * regardless of whether the phar extension is available. The first parameter
    3050                 :  * is the CLI startup filename, which defaults to "index.php". The second
    3051                 :  * parameter is the web startup filename and also defaults to "index.php"
    3052                 :  * (falling back to CLI behaviour).
    3053                 :  * Both parameters are optional.
    3054                 :  * In a phar.zip or phar.tar archive, the default stub is used only to
    3055                 :  * identify the archive to the extension as a Phar object. This allows the
    3056                 :  * extension to treat phar.zip and phar.tar types as honorary phars. Since
    3057                 :  * files cannot be loaded via this kind of stub, no parameters are accepted
    3058                 :  * when the Phar object is zip- or tar-based.
    3059                 :  */
    3060                 : PHP_METHOD(Phar, setDefaultStub)
    3061              19 : {
    3062              19 :         char *index = NULL, *webindex = NULL, *error = NULL, *stub = NULL;
    3063              19 :         int index_len = 0, webindex_len = 0, created_stub = 0;
    3064              19 :         size_t stub_len = 0;
    3065              19 :         PHAR_ARCHIVE_OBJECT();
    3066                 : 
    3067              19 :         if (phar_obj->arc.archive->is_data) {
    3068               3 :                 if (phar_obj->arc.archive->is_tar) {
    3069               2 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3070                 :                                 "A Phar stub cannot be set in a plain tar archive");
    3071                 :                 } else {
    3072               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3073                 :                                 "A Phar stub cannot be set in a plain zip archive");
    3074                 :                 }
    3075               3 :                 return;
    3076                 :         }
    3077                 : 
    3078              16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
    3079               1 :                 RETURN_FALSE;
    3080                 :         }
    3081                 : 
    3082              15 :         if (ZEND_NUM_ARGS() > 0 && (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip)) {
    3083               4 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "method accepts no arguments for a tar- or zip-based phar stub, %d given", ZEND_NUM_ARGS());
    3084               4 :                 RETURN_FALSE;
    3085                 :         }
    3086                 : 
    3087              11 :         if (PHAR_G(readonly)) {
    3088               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3089                 :                         "Cannot change stub: phar.readonly=1");
    3090               1 :                 RETURN_FALSE;
    3091                 :         }
    3092                 : 
    3093              10 :         if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) {
    3094               8 :                 stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
    3095                 : 
    3096               8 :                 if (error) {
    3097               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, error);
    3098               1 :                         efree(error);
    3099               1 :                         if (stub) {
    3100               0 :                                 efree(stub);
    3101                 :                         }
    3102               1 :                         RETURN_FALSE;
    3103                 :                 }
    3104                 : 
    3105               7 :                 created_stub = 1;
    3106                 :         }
    3107                 : 
    3108               9 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3109               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3110               0 :                 return;
    3111                 :         }
    3112               9 :         phar_flush(phar_obj->arc.archive, stub, stub_len, 1, &error TSRMLS_CC);
    3113                 : 
    3114               9 :         if (created_stub) {
    3115               7 :                 efree(stub);
    3116                 :         }
    3117                 : 
    3118               9 :         if (error) {
    3119               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3120               0 :                 efree(error);
    3121               0 :                 RETURN_FALSE;
    3122                 :         }
    3123                 : 
    3124               9 :         RETURN_TRUE;
    3125                 : }
    3126                 : /* }}} */
    3127                 : 
    3128                 : /* {{{ proto array Phar::setSignatureAlgorithm(int sigtype[, string privatekey])
    3129                 :  * Sets the signature algorithm for a phar and applies it. The signature
    3130                 :  * algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256,
    3131                 :  * Phar::SHA512, or Phar::OPENSSL. Note that zip- based phar archives
    3132                 :  * cannot support signatures.
    3133                 :  */
    3134                 : PHP_METHOD(Phar, setSignatureAlgorithm)
    3135              18 : {
    3136                 :         long algo;
    3137              18 :         char *error, *key = NULL;
    3138              18 :         int key_len = 0;
    3139                 : 
    3140              18 :         PHAR_ARCHIVE_OBJECT();
    3141                 : 
    3142              18 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3143               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3144                 :                         "Cannot set signature algorithm, phar is read-only");
    3145               1 :                 return;
    3146                 :         }
    3147                 : 
    3148              17 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &algo, &key, &key_len) != SUCCESS) {
    3149               0 :                 return;
    3150                 :         }
    3151                 : 
    3152              17 :         switch (algo) {
    3153                 :                 case PHAR_SIG_SHA256:
    3154                 :                 case PHAR_SIG_SHA512:
    3155                 : #ifndef PHAR_HASH_OK
    3156                 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3157                 :                                 "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled and built non-shared");
    3158                 :                         return;
    3159                 : #endif
    3160                 :                 case PHAR_SIG_MD5:
    3161                 :                 case PHAR_SIG_SHA1:
    3162                 :                 case PHAR_SIG_OPENSSL:
    3163              17 :                         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3164               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3165               0 :                                 return;
    3166                 :                         }
    3167              17 :                         phar_obj->arc.archive->sig_flags = algo;
    3168              17 :                         phar_obj->arc.archive->is_modified = 1;
    3169              17 :                         PHAR_G(openssl_privatekey) = key;
    3170              17 :                         PHAR_G(openssl_privatekey_len) = key_len;
    3171                 : 
    3172              17 :                         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    3173              17 :                         if (error) {
    3174               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3175               0 :                                 efree(error);
    3176                 :                         }
    3177              17 :                         break;
    3178                 :                 default:
    3179               0 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3180                 :                                 "Unknown signature algorithm specified");
    3181                 :         }
    3182                 : }
    3183                 : /* }}} */
    3184                 : 
    3185                 : /* {{{ proto array|false Phar::getSignature()
    3186                 :  * Returns a hash signature, or FALSE if the archive is unsigned.
    3187                 :  */
    3188                 : PHP_METHOD(Phar, getSignature)
    3189              31 : {
    3190              31 :         PHAR_ARCHIVE_OBJECT();
    3191                 : 
    3192              31 :         if (phar_obj->arc.archive->signature) {
    3193                 :                 char *unknown;
    3194                 :                 int unknown_len;
    3195                 : 
    3196              29 :                 array_init(return_value);
    3197              29 :                 add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1);
    3198              29 :                 switch(phar_obj->arc.archive->sig_flags) {
    3199                 :                         case PHAR_SIG_MD5:
    3200               6 :                                 add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1);
    3201               6 :                                 break;
    3202                 :                         case PHAR_SIG_SHA1:
    3203              11 :                                 add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1);
    3204              11 :                                 break;
    3205                 :                         case PHAR_SIG_SHA256:
    3206               4 :                                 add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1);
    3207               4 :                                 break;
    3208                 :                         case PHAR_SIG_SHA512:
    3209               4 :                                 add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1);
    3210               4 :                                 break;
    3211                 :                         case PHAR_SIG_OPENSSL:
    3212               4 :                                 add_assoc_stringl(return_value, "hash_type", "OpenSSL", 7, 1);
    3213               4 :                                 break;
    3214                 :                         default:
    3215               0 :                                 unknown_len = spprintf(&unknown, 0, "Unknown (%u)", phar_obj->arc.archive->sig_flags);
    3216               0 :                                 add_assoc_stringl(return_value, "hash_type", unknown, unknown_len, 0);
    3217                 :                                 break;
    3218                 :                 }
    3219                 :         } else {
    3220               2 :                 RETURN_FALSE;
    3221                 :         }
    3222                 : }
    3223                 : /* }}} */
    3224                 : 
    3225                 : /* {{{ proto bool Phar::getModified()
    3226                 :  * Return whether phar was modified
    3227                 :  */
    3228                 : PHP_METHOD(Phar, getModified)
    3229               2 : {
    3230               2 :         PHAR_ARCHIVE_OBJECT();
    3231                 : 
    3232               2 :         RETURN_BOOL(phar_obj->arc.archive->is_modified);
    3233                 : }
    3234                 : /* }}} */
    3235                 : 
    3236                 : static int phar_set_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
    3237              35 : {
    3238              35 :         phar_entry_info *entry = (phar_entry_info *)pDest;
    3239              35 :         php_uint32 compress = *(php_uint32 *)argument;
    3240                 : 
    3241              35 :         if (entry->is_deleted) {
    3242               0 :                 return ZEND_HASH_APPLY_KEEP;
    3243                 :         }
    3244                 : 
    3245              35 :         entry->old_flags = entry->flags;
    3246              35 :         entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
    3247              35 :         entry->flags |= compress;
    3248              35 :         entry->is_modified = 1;
    3249              35 :         return ZEND_HASH_APPLY_KEEP;
    3250                 : }
    3251                 : /* }}} */
    3252                 : 
    3253                 : static int phar_test_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
    3254              35 : {
    3255              35 :         phar_entry_info *entry = (phar_entry_info *)pDest;
    3256                 : 
    3257              35 :         if (entry->is_deleted) {
    3258               0 :                 return ZEND_HASH_APPLY_KEEP;
    3259                 :         }
    3260                 : 
    3261              35 :         if (!PHAR_G(has_bz2)) {
    3262               0 :                 if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
    3263               0 :                         *(int *) argument = 0;
    3264                 :                 }
    3265                 :         }
    3266                 : 
    3267              35 :         if (!PHAR_G(has_zlib)) {
    3268               0 :                 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
    3269               0 :                         *(int *) argument = 0;
    3270                 :                 }
    3271                 :         }
    3272                 : 
    3273              35 :         return ZEND_HASH_APPLY_KEEP;
    3274                 : }
    3275                 : /* }}} */
    3276                 : 
    3277                 : static void pharobj_set_compression(HashTable *manifest, php_uint32 compress TSRMLS_DC) /* {{{ */
    3278              11 : {
    3279              11 :         zend_hash_apply_with_argument(manifest, phar_set_compression, &compress TSRMLS_CC);
    3280              11 : }
    3281                 : /* }}} */
    3282                 : 
    3283                 : static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */
    3284              11 : {
    3285                 :         int test;
    3286                 : 
    3287              11 :         test = 1;
    3288              11 :         zend_hash_apply_with_argument(manifest, phar_test_compression, &test TSRMLS_CC);
    3289              11 :         return test;
    3290                 : }
    3291                 : /* }}} */
    3292                 : 
    3293                 : /* {{{ proto object Phar::compress(int method[, string extension])
    3294                 :  * Compress a .tar, or .phar.tar with whole-file compression
    3295                 :  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
    3296                 :  * the kind of compression desired
    3297                 :  */
    3298                 : PHP_METHOD(Phar, compress)
    3299               6 : {
    3300                 :         long method;
    3301               6 :         char *ext = NULL;
    3302               6 :         int ext_len = 0;
    3303                 :         php_uint32 flags;
    3304                 :         zval *ret;
    3305               6 :         PHAR_ARCHIVE_OBJECT();
    3306                 : 
    3307               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &method, &ext, &ext_len) == FAILURE) {
    3308               1 :                 return;
    3309                 :         }
    3310                 : 
    3311               5 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3312               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3313                 :                         "Cannot compress phar archive, phar is read-only");
    3314               1 :                 return;
    3315                 :         }
    3316                 : 
    3317               4 :         if (phar_obj->arc.archive->is_zip) {
    3318               0 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3319                 :                         "Cannot compress zip-based archives with whole-archive compression");
    3320               0 :                 return;
    3321                 :         }
    3322                 : 
    3323               4 :         switch (method) {
    3324                 :                 case 0:
    3325               1 :                         flags = PHAR_FILE_COMPRESSED_NONE;
    3326               1 :                         break;
    3327                 :                 case PHAR_ENT_COMPRESSED_GZ:
    3328               2 :                         if (!PHAR_G(has_zlib)) {
    3329               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3330                 :                                         "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
    3331               0 :                                 return;
    3332                 :                         }
    3333               2 :                         flags = PHAR_FILE_COMPRESSED_GZ;
    3334               2 :                         break;
    3335                 : 
    3336                 :                 case PHAR_ENT_COMPRESSED_BZ2:
    3337               1 :                         if (!PHAR_G(has_bz2)) {
    3338               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3339                 :                                         "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
    3340               0 :                                 return;
    3341                 :                         }
    3342               1 :                         flags = PHAR_FILE_COMPRESSED_BZ2;
    3343               1 :                         break;
    3344                 :                 default:
    3345               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3346                 :                                 "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
    3347               0 :                         return;
    3348                 :         }
    3349                 : 
    3350               4 :         if (phar_obj->arc.archive->is_tar) {
    3351               2 :                 ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, flags TSRMLS_CC);
    3352                 :         } else {
    3353               2 :                 ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, flags TSRMLS_CC);
    3354                 :         }
    3355                 : 
    3356               4 :         if (ret) {
    3357               4 :                 RETURN_ZVAL(ret, 1, 1);
    3358                 :         } else {
    3359               0 :                 RETURN_NULL();
    3360                 :         }
    3361                 : }
    3362                 : /* }}} */
    3363                 : 
    3364                 : /* {{{ proto object Phar::decompress([string extension])
    3365                 :  * Decompress a .tar, or .phar.tar with whole-file compression
    3366                 :  */
    3367                 : PHP_METHOD(Phar, decompress)
    3368               5 : {
    3369               5 :         char *ext = NULL;
    3370               5 :         int ext_len = 0;
    3371                 :         zval *ret;
    3372               5 :         PHAR_ARCHIVE_OBJECT();
    3373                 : 
    3374               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ext, &ext_len) == FAILURE) {
    3375               1 :                 return;
    3376                 :         }
    3377                 : 
    3378               4 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3379               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3380                 :                         "Cannot decompress phar archive, phar is read-only");
    3381               1 :                 return;
    3382                 :         }
    3383                 : 
    3384               3 :         if (phar_obj->arc.archive->is_zip) {
    3385               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3386                 :                         "Cannot decompress zip-based archives with whole-archive compression");
    3387               1 :                 return;
    3388                 :         }
    3389                 : 
    3390               2 :         if (phar_obj->arc.archive->is_tar) {
    3391               0 :                 ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
    3392                 :         } else {
    3393               2 :                 ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
    3394                 :         }
    3395                 : 
    3396               2 :         if (ret) {
    3397               2 :                 RETURN_ZVAL(ret, 1, 1);
    3398                 :         } else {
    3399               0 :                 RETURN_NULL();
    3400                 :         }
    3401                 : }
    3402                 : /* }}} */
    3403                 : 
    3404                 : /* {{{ proto object Phar::compressFiles(int method)
    3405                 :  * Compress all files within a phar or zip archive using the specified compression
    3406                 :  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
    3407                 :  * the kind of compression desired
    3408                 :  */
    3409                 : PHP_METHOD(Phar, compressFiles)
    3410              11 : {
    3411                 :         char *error;
    3412                 :         php_uint32 flags;
    3413                 :         long method;
    3414              11 :         PHAR_ARCHIVE_OBJECT();
    3415                 : 
    3416              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
    3417               1 :                 return;
    3418                 :         }
    3419                 : 
    3420              10 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3421               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3422                 :                         "Phar is readonly, cannot change compression");
    3423               0 :                 return;
    3424                 :         }
    3425                 : 
    3426              10 :         switch (method) {
    3427                 :                 case PHAR_ENT_COMPRESSED_GZ:
    3428               6 :                         if (!PHAR_G(has_zlib)) {
    3429               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3430                 :                                         "Cannot compress files within archive with gzip, enable ext/zlib in php.ini");
    3431               0 :                                 return;
    3432                 :                         }
    3433               6 :                         flags = PHAR_ENT_COMPRESSED_GZ;
    3434               6 :                         break;
    3435                 : 
    3436                 :                 case PHAR_ENT_COMPRESSED_BZ2:
    3437               3 :                         if (!PHAR_G(has_bz2)) {
    3438               0 :                                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3439                 :                                         "Cannot compress files within archive with bz2, enable ext/bz2 in php.ini");
    3440               0 :                                 return;
    3441                 :                         }
    3442               3 :                         flags = PHAR_ENT_COMPRESSED_BZ2;
    3443               3 :                         break;
    3444                 :                 default:
    3445               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3446                 :                                 "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
    3447               1 :                         return;
    3448                 :         }
    3449                 : 
    3450               9 :         if (phar_obj->arc.archive->is_tar) {
    3451               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3452                 :                         "Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive");
    3453               0 :                 return;
    3454                 :         }
    3455                 : 
    3456               9 :         if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
    3457               0 :                 if (flags == PHAR_FILE_COMPRESSED_GZ) {
    3458               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3459                 :                                 "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed");
    3460                 :                 } else {
    3461               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3462                 :                                 "Cannot compress all files as Bzip2, some are compressed as gzip and cannot be decompressed");
    3463                 :                 }
    3464               0 :                 return;
    3465                 :         }
    3466                 : 
    3467               9 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3468               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3469               0 :                 return;
    3470                 :         }
    3471               9 :         pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC);
    3472               9 :         phar_obj->arc.archive->is_modified = 1;
    3473               9 :         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    3474                 : 
    3475               9 :         if (error) {
    3476               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
    3477               0 :                 efree(error);
    3478                 :         }
    3479                 : }
    3480                 : /* }}} */
    3481                 : 
    3482                 : /* {{{ proto bool Phar::decompressFiles()
    3483                 :  * decompress every file
    3484                 :  */
    3485                 : PHP_METHOD(Phar, decompressFiles)
    3486               3 : {
    3487                 :         char *error;
    3488               3 :         PHAR_ARCHIVE_OBJECT();
    3489                 : 
    3490               3 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3491               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3492                 :                         "Phar is readonly, cannot change compression");
    3493               1 :                 return;
    3494                 :         }
    3495                 : 
    3496               2 :         if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
    3497               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
    3498                 :                         "Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed");
    3499               0 :                 return;
    3500                 :         }
    3501                 : 
    3502               2 :         if (phar_obj->arc.archive->is_tar) {
    3503               0 :                 RETURN_TRUE;
    3504                 :         } else {
    3505               2 :                 if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3506               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3507               0 :                         return;
    3508                 :                 }
    3509               2 :                 pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_NONE TSRMLS_CC);
    3510                 :         }
    3511                 : 
    3512               2 :         phar_obj->arc.archive->is_modified = 1;
    3513               2 :         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    3514                 : 
    3515               2 :         if (error) {
    3516               0 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
    3517               0 :                 efree(error);
    3518                 :         }
    3519                 : 
    3520               2 :         RETURN_TRUE;
    3521                 : }
    3522                 : /* }}} */
    3523                 : 
    3524                 : /* {{{ proto bool Phar::copy(string oldfile, string newfile)
    3525                 :  * copy a file internal to the phar archive to another new file within the phar
    3526                 :  */
    3527                 : PHP_METHOD(Phar, copy)
    3528              17 : {
    3529                 :         char *oldfile, *newfile, *error;
    3530                 :         const char *pcr_error;
    3531                 :         int oldfile_len, newfile_len;
    3532              17 :         phar_entry_info *oldentry, newentry = {0}, *temp;
    3533                 : 
    3534              17 :         PHAR_ARCHIVE_OBJECT();
    3535                 : 
    3536              17 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) {
    3537               1 :                 return;
    3538                 :         }
    3539                 : 
    3540              16 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3541               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3542                 :                         "Cannot copy \"%s\" to \"%s\", phar is read-only", oldfile, newfile);
    3543               1 :                 RETURN_FALSE;
    3544                 :         }
    3545                 : 
    3546              15 :         if (oldfile_len >= sizeof(".phar")-1 && !memcmp(oldfile, ".phar", sizeof(".phar")-1)) {
    3547                 :                 /* can't copy a meta file */
    3548               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3549                 :                         "file \"%s\" cannot be copied to file \"%s\", cannot copy Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname);
    3550               1 :                 RETURN_FALSE;
    3551                 :         }
    3552                 : 
    3553              14 :         if (newfile_len >= sizeof(".phar")-1 && !memcmp(newfile, ".phar", sizeof(".phar")-1)) {
    3554                 :                 /* can't copy a meta file */
    3555               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3556                 :                         "file \"%s\" cannot be copied to file \"%s\", cannot copy to Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname);
    3557               1 :                 RETURN_FALSE;
    3558                 :         }
    3559                 : 
    3560              13 :         if (!zend_hash_exists(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len) || SUCCESS != zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry) || oldentry->is_deleted) {
    3561               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3562                 :                         "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->arc.archive->fname);
    3563               1 :                 RETURN_FALSE;
    3564                 :         }
    3565                 : 
    3566              12 :         if (zend_hash_exists(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len)) {
    3567               1 :                 if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len, (void**)&temp) || !temp->is_deleted) {
    3568               1 :                         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3569                 :                                 "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->arc.archive->fname);
    3570               1 :                         RETURN_FALSE;
    3571                 :                 }
    3572                 :         }
    3573                 : 
    3574              11 :         if (phar_path_check(&newfile, &newfile_len, &pcr_error) > pcr_is_ok) {
    3575               3 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
    3576                 :                                 "file \"%s\" contains invalid characters %s, cannot be copied from \"%s\" in phar %s", newfile, pcr_error, oldfile, phar_obj->arc.archive->fname);
    3577               3 :                 RETURN_FALSE;
    3578                 :         }
    3579                 : 
    3580               8 :         if (phar_obj->arc.archive->is_persistent) {
    3581               0 :                 if (FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3582               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3583               0 :                         return;
    3584                 :                 }
    3585                 :                 /* re-populate with copied-on-write entry */
    3586               0 :                 zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry);
    3587                 :         }
    3588                 : 
    3589               8 :         memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info));
    3590                 : 
    3591               8 :         if (newentry.metadata) {
    3592                 :                 zval *t;
    3593                 : 
    3594               1 :                 t = newentry.metadata;
    3595               1 :                 ALLOC_ZVAL(newentry.metadata);
    3596               1 :                 *newentry.metadata = *t;
    3597               1 :                 zval_copy_ctor(newentry.metadata);
    3598                 : #if PHP_VERSION_ID < 50300
    3599                 :                 newentry.metadata->refcount = 1;
    3600                 : #else
    3601               1 :                 Z_SET_REFCOUNT_P(newentry.metadata, 1);
    3602                 : #endif
    3603                 : 
    3604               1 :                 newentry.metadata_str.c = NULL;
    3605               1 :                 newentry.metadata_str.len = 0;
    3606                 :         }
    3607                 : 
    3608               8 :         newentry.filename = estrndup(newfile, newfile_len);
    3609               8 :         newentry.filename_len = newfile_len;
    3610               8 :         newentry.fp_refcount = 0;
    3611                 : 
    3612               8 :         if (oldentry->fp_type != PHAR_FP) {
    3613               1 :                 if (FAILURE == phar_copy_entry_fp(oldentry, &newentry, &error TSRMLS_CC)) {
    3614               0 :                         efree(newentry.filename);
    3615               0 :                         php_stream_close(newentry.fp);
    3616               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3617               0 :                         efree(error);
    3618               0 :                         return;
    3619                 :                 }
    3620                 :         }
    3621                 : 
    3622               8 :         zend_hash_add(&oldentry->phar->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
    3623               8 :         phar_obj->arc.archive->is_modified = 1;
    3624               8 :         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    3625                 : 
    3626               8 :         if (error) {
    3627               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3628               0 :                 efree(error);
    3629                 :         }
    3630                 : 
    3631               8 :         RETURN_TRUE;
    3632                 : }
    3633                 : /* }}} */
    3634                 : 
    3635                 : /* {{{ proto int Phar::offsetExists(string entry)
    3636                 :  * determines whether a file exists in the phar
    3637                 :  */
    3638                 : PHP_METHOD(Phar, offsetExists)
    3639              34 : {
    3640                 :         char *fname;
    3641                 :         int fname_len;
    3642                 :         phar_entry_info *entry;
    3643                 : 
    3644              34 :         PHAR_ARCHIVE_OBJECT();
    3645                 : 
    3646              34 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    3647               1 :                 return;
    3648                 :         }
    3649                 : 
    3650              33 :         if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
    3651              19 :                 if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
    3652              19 :                         if (entry->is_deleted) {
    3653                 :                                 /* entry is deleted, but has not been flushed to disk yet */
    3654               0 :                                 RETURN_FALSE;
    3655                 :                         }
    3656                 :                 }
    3657                 : 
    3658              19 :                 if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
    3659                 :                         /* none of these are real files, so they don't exist */
    3660               2 :                         RETURN_FALSE;
    3661                 :                 }
    3662              17 :                 RETURN_TRUE;
    3663                 :         } else {
    3664              14 :                 if (zend_hash_exists(&phar_obj->arc.archive->virtual_dirs, fname, (uint) fname_len)) {
    3665               3 :                         RETURN_TRUE;
    3666                 :                 }
    3667              11 :                 RETURN_FALSE;
    3668                 :         }
    3669                 : }
    3670                 : /* }}} */
    3671                 : 
    3672                 : /* {{{ proto int Phar::offsetGet(string entry)
    3673                 :  * get a PharFileInfo object for a specific file
    3674                 :  */
    3675                 : PHP_METHOD(Phar, offsetGet)
    3676             332 : {
    3677                 :         char *fname, *error;
    3678                 :         int fname_len;
    3679                 :         zval *zfname;
    3680                 :         phar_entry_info *entry;
    3681             332 :         PHAR_ARCHIVE_OBJECT();
    3682                 : 
    3683             332 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    3684               1 :                 return;
    3685                 :         }
    3686                 : 
    3687                 :         /* security is 0 here so that we can get a better error message than "entry doesn't exist" */
    3688             331 :         if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error, 0 TSRMLS_CC))) {
    3689               3 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:"");
    3690                 :         } else {
    3691             328 :                 if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
    3692               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get stub \".phar/stub.php\" directly in phar \"%s\", use getStub", phar_obj->arc.archive->fname);
    3693               0 :                         return;
    3694                 :                 }
    3695                 : 
    3696             328 :                 if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
    3697               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get alias \".phar/alias.txt\" directly in phar \"%s\", use getAlias", phar_obj->arc.archive->fname);
    3698               0 :                         return;
    3699                 :                 }
    3700                 : 
    3701             328 :                 if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
    3702               1 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot directly get any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname);
    3703               1 :                         return;
    3704                 :                 }
    3705                 : 
    3706             327 :                 if (entry->is_temp_dir) {
    3707               6 :                         efree(entry->filename);
    3708               6 :                         efree(entry);
    3709                 :                 }
    3710                 : 
    3711             327 :                 fname_len = spprintf(&fname, 0, "phar://%s/%s", phar_obj->arc.archive->fname, fname);
    3712             327 :                 MAKE_STD_ZVAL(zfname);
    3713             327 :                 ZVAL_STRINGL(zfname, fname, fname_len, 0);
    3714             327 :                 spl_instantiate_arg_ex1(phar_obj->spl.info_class, &return_value, 0, zfname TSRMLS_CC);
    3715             327 :                 zval_ptr_dtor(&zfname);
    3716                 :         }
    3717                 : }
    3718                 : /* }}} */
    3719                 : 
    3720                 : /* {{{ add a file within the phar archive from a string or resource
    3721                 :  */
    3722                 : static void phar_add_file(phar_archive_data **pphar, char *filename, int filename_len, char *cont_str, int cont_len, zval *zresource TSRMLS_DC)
    3723            4343 : {
    3724                 :         char *error;
    3725                 :         size_t contents_len;
    3726                 :         phar_entry_data *data;
    3727                 :         php_stream *contents_file;
    3728                 : 
    3729            4343 :         if (filename_len >= sizeof(".phar")-1 && !memcmp(filename, ".phar", sizeof(".phar")-1)) {
    3730               2 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create any files in magic \".phar\" directory", (*pphar)->fname);
    3731               2 :                 return;
    3732                 :         }
    3733                 : 
    3734            4341 :         if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, filename, filename_len, "w+b", 0, &error, 1 TSRMLS_CC))) {
    3735               4 :                 if (error) {
    3736               4 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created: %s", filename, error);
    3737               4 :                         efree(error);
    3738                 :                 } else {
    3739               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created", filename);
    3740                 :                 }
    3741               4 :                 return;
    3742                 :         } else {
    3743            4337 :                 if (error) {
    3744               0 :                         efree(error);
    3745                 :                 }
    3746                 : 
    3747            4337 :                 if (!data->internal_file->is_dir) {
    3748            4337 :                         if (cont_str) {
    3749             240 :                                 contents_len = php_stream_write(data->fp, cont_str, cont_len);
    3750             240 :                                 if (contents_len != cont_len) {
    3751               0 :                                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
    3752               0 :                                         return;
    3753                 :                                 }
    3754                 :                         } else {
    3755            4097 :                                 if (!(php_stream_from_zval_no_verify(contents_file, &zresource))) {
    3756               0 :                                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
    3757               0 :                                         return;
    3758                 :                                 }
    3759            4097 :                                 phar_stream_copy_to_stream(contents_file, data->fp, PHP_STREAM_COPY_ALL, &contents_len);
    3760                 :                         }
    3761                 : 
    3762            4337 :                         data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
    3763                 :                 }
    3764                 : 
    3765                 :                 /* check for copy-on-write */
    3766            4337 :                 if (pphar[0] != data->phar) {
    3767               0 :                         *pphar = data->phar;
    3768                 :                 }
    3769            4337 :                 phar_entry_delref(data TSRMLS_CC);
    3770            4337 :                 phar_flush(*pphar, 0, 0, 0, &error TSRMLS_CC);
    3771                 : 
    3772            4337 :                 if (error) {
    3773               4 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3774               4 :                         efree(error);
    3775                 :                 }
    3776                 :         }
    3777                 : }
    3778                 : /* }}} */
    3779                 : 
    3780                 : /* {{{ create a directory within the phar archive
    3781                 :  */
    3782                 : static void phar_mkdir(phar_archive_data **pphar, char *dirname, int dirname_len TSRMLS_DC)
    3783              18 : {
    3784                 :         char *error;
    3785                 :         phar_entry_data *data;
    3786                 : 
    3787              18 :         if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, dirname, dirname_len, "w+b", 2, &error, 1 TSRMLS_CC))) {
    3788               0 :                 if (error) {
    3789               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created: %s", dirname, error);
    3790               0 :                         efree(error);
    3791                 :                 } else {
    3792               0 :                         zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created", dirname);
    3793                 :                 }
    3794                 : 
    3795               0 :                 return;
    3796                 :         } else {
    3797              18 :                 if (error) {
    3798               0 :                         efree(error);
    3799                 :                 }
    3800                 : 
    3801                 :                 /* check for copy on write */
    3802              18 :                 if (data->phar != *pphar) {
    3803               0 :                         *pphar = data->phar;
    3804                 :                 }
    3805              18 :                 phar_entry_delref(data TSRMLS_CC);
    3806              18 :                 phar_flush(*pphar, 0, 0, 0, &error TSRMLS_CC);
    3807                 : 
    3808              18 :                 if (error) {
    3809               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3810               0 :                         efree(error);
    3811                 :                 }
    3812                 :         }
    3813                 : }
    3814                 : /* }}} */
    3815                 : 
    3816                 : /* {{{ proto int Phar::offsetSet(string entry, string value)
    3817                 :  * set the contents of an internal file to those of an external file
    3818                 :  */
    3819                 : PHP_METHOD(Phar, offsetSet)
    3820             250 : {
    3821             250 :         char *fname, *cont_str = NULL;
    3822                 :         int fname_len, cont_len;
    3823                 :         zval *zresource;
    3824             250 :         PHAR_ARCHIVE_OBJECT();
    3825                 : 
    3826             250 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3827               3 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
    3828               3 :                 return;
    3829                 :         }
    3830                 : 
    3831             247 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sr", &fname, &fname_len, &zresource) == FAILURE
    3832                 :         && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) {
    3833               1 :                 return;
    3834                 :         }
    3835                 : 
    3836             246 :         if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
    3837               3 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set stub \".phar/stub.php\" directly in phar \"%s\", use setStub", phar_obj->arc.archive->fname);
    3838               3 :                 return;
    3839                 :         }
    3840                 : 
    3841             243 :         if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
    3842               4 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set alias \".phar/alias.txt\" directly in phar \"%s\", use setAlias", phar_obj->arc.archive->fname);
    3843               4 :                 return;
    3844                 :         }
    3845                 : 
    3846             239 :         if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
    3847               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname);
    3848               1 :                 return;
    3849                 :         }
    3850                 : 
    3851             238 :         phar_add_file(&(phar_obj->arc.archive), fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC);
    3852                 : }
    3853                 : /* }}} */
    3854                 : 
    3855                 : /* {{{ proto int Phar::offsetUnset(string entry)
    3856                 :  * remove a file from a phar
    3857                 :  */
    3858                 : PHP_METHOD(Phar, offsetUnset)
    3859               7 : {
    3860                 :         char *fname, *error;
    3861                 :         int fname_len;
    3862                 :         phar_entry_info *entry;
    3863               7 :         PHAR_ARCHIVE_OBJECT();
    3864                 : 
    3865               7 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    3866               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
    3867               1 :                 return;
    3868                 :         }
    3869                 : 
    3870               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    3871               1 :                 return;
    3872                 :         }
    3873                 : 
    3874               5 :         if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
    3875               3 :                 if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
    3876               3 :                         if (entry->is_deleted) {
    3877                 :                                 /* entry is deleted, but has not been flushed to disk yet */
    3878               0 :                                 return;
    3879                 :                         }
    3880                 : 
    3881               3 :                         if (phar_obj->arc.archive->is_persistent) {
    3882               0 :                                 if (FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    3883               0 :                                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    3884               0 :                                         return;
    3885                 :                                 }
    3886                 :                                 /* re-populate entry after copy on write */
    3887               0 :                                 zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void **)&entry);
    3888                 :                         }
    3889               3 :                         entry->is_modified = 0;
    3890               3 :                         entry->is_deleted = 1;
    3891                 :                         /* we need to "flush" the stream to save the newly deleted file on disk */
    3892               3 :                         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    3893                 : 
    3894               3 :                         if (error) {
    3895               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    3896               0 :                                 efree(error);
    3897                 :                         }
    3898                 : 
    3899               3 :                         RETURN_TRUE;
    3900                 :                 }
    3901                 :         } else {
    3902               2 :                 RETURN_FALSE;
    3903                 :         }
    3904                 : }
    3905                 : /* }}} */
    3906                 : 
    3907                 : /* {{{ proto string Phar::addEmptyDir(string dirname)
    3908                 :  * Adds an empty directory to the phar archive
    3909                 :  */
    3910                 : PHP_METHOD(Phar, addEmptyDir)
    3911              20 : {
    3912                 :         char *dirname;
    3913                 :         int dirname_len;
    3914                 : 
    3915              20 :         PHAR_ARCHIVE_OBJECT();
    3916                 : 
    3917              20 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dirname, &dirname_len) == FAILURE) {
    3918               1 :                 return;
    3919                 :         }
    3920                 : 
    3921              19 :         if (dirname_len >= sizeof(".phar")-1 && !memcmp(dirname, ".phar", sizeof(".phar")-1)) {
    3922               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create a directory in magic \".phar\" directory");
    3923               1 :                 return;
    3924                 :         }
    3925                 : 
    3926              18 :         phar_mkdir(&phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC);
    3927                 : }
    3928                 : /* }}} */
    3929                 : 
    3930                 : /* {{{ proto string Phar::addFile(string filename[, string localname])
    3931                 :  * Adds a file to the archive using the filename, or the second parameter as the name within the archive
    3932                 :  */
    3933                 : PHP_METHOD(Phar, addFile)
    3934            4102 : {
    3935            4102 :         char *fname, *localname = NULL;
    3936            4102 :         int fname_len, localname_len = 0;
    3937                 :         php_stream *resource;
    3938                 :         zval *zresource;
    3939                 : 
    3940            4102 :         PHAR_ARCHIVE_OBJECT();
    3941                 : 
    3942            4102 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) {
    3943               1 :                 return;
    3944                 :         }
    3945                 : 
    3946                 : #if PHP_MAJOR_VERSION < 6
    3947            4101 :         if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
    3948               0 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, safe_mode restrictions prevent this", fname);
    3949               0 :                 return;
    3950                 :         }
    3951                 : #endif
    3952                 : 
    3953            4101 :         if (!strstr(fname, "://") && php_check_open_basedir(fname TSRMLS_CC)) {
    3954               0 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, open_basedir restrictions prevent this", fname);
    3955               0 :                 return;
    3956                 :         }
    3957                 : 
    3958            4101 :         if (!(resource = php_stream_open_wrapper(fname, "rb", 0, NULL))) {
    3959               1 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive", fname);
    3960               1 :                 return;
    3961                 :         }
    3962                 : 
    3963            4100 :         if (localname) {
    3964            4099 :                 fname = localname;
    3965            4099 :                 fname_len = localname_len;
    3966                 :         }
    3967                 : 
    3968            4100 :         MAKE_STD_ZVAL(zresource);
    3969            4100 :         php_stream_to_zval(resource, zresource);
    3970            4100 :         phar_add_file(&(phar_obj->arc.archive), fname, fname_len, NULL, 0, zresource TSRMLS_CC);
    3971            4100 :         efree(zresource);
    3972            4100 :         php_stream_close(resource);
    3973                 : }
    3974                 : /* }}} */
    3975                 : 
    3976                 : /* {{{ proto string Phar::addFromString(string localname, string contents)
    3977                 :  * Adds a file to the archive using its contents as a string
    3978                 :  */
    3979                 : PHP_METHOD(Phar, addFromString)
    3980               6 : {
    3981                 :         char *localname, *cont_str;
    3982                 :         int localname_len, cont_len;
    3983                 : 
    3984               6 :         PHAR_ARCHIVE_OBJECT();
    3985                 : 
    3986               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) {
    3987               1 :                 return;
    3988                 :         }
    3989                 : 
    3990               5 :         phar_add_file(&(phar_obj->arc.archive), localname, localname_len, cont_str, cont_len, NULL TSRMLS_CC);
    3991                 : }
    3992                 : /* }}} */
    3993                 : 
    3994                 : /* {{{ proto string Phar::getStub()
    3995                 :  * Returns the stub at the head of a phar archive as a string.
    3996                 :  */
    3997                 : PHP_METHOD(Phar, getStub)
    3998             137 : {
    3999                 :         size_t len;
    4000                 :         char *buf;
    4001                 :         php_stream *fp;
    4002             137 :         php_stream_filter *filter = NULL;
    4003                 :         phar_entry_info *stub;
    4004                 : 
    4005             137 :         PHAR_ARCHIVE_OBJECT();
    4006                 : 
    4007             137 :         if (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) {
    4008                 : 
    4009              70 :                 if (SUCCESS == zend_hash_find(&(phar_obj->arc.archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
    4010             128 :                         if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew && !(stub->flags & PHAR_ENT_COMPRESSION_MASK)) {
    4011              64 :                                 fp = phar_obj->arc.archive->fp;
    4012                 :                         } else {
    4013               0 :                                 fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL);
    4014               0 :                                 if (stub->flags & PHAR_ENT_COMPRESSION_MASK) {
    4015                 :                                         char *filter_name;
    4016                 : 
    4017               0 :                                         if ((filter_name = phar_decompress_filter(stub, 0)) != NULL) {
    4018               0 :                                                 filter = php_stream_filter_create(filter_name, NULL, php_stream_is_persistent(fp) TSRMLS_CC);
    4019                 :                                         } else {
    4020               0 :                                                 filter = NULL;
    4021                 :                                         }
    4022               0 :                                         if (!filter) {
    4023               0 :                                                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", phar_obj->arc.archive->fname, phar_decompress_filter(stub, 1));
    4024               0 :                                                 return;
    4025                 :                                         }
    4026               0 :                                         php_stream_filter_append(&fp->readfilters, filter);
    4027                 :                                 }
    4028                 :                         }
    4029                 : 
    4030              64 :                         if (!fp)  {
    4031               0 :                                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4032                 :                                         "Unable to read stub");
    4033               0 :                                 return;
    4034                 :                         }
    4035                 : 
    4036              64 :                         php_stream_seek(fp, stub->offset_abs, SEEK_SET);
    4037              64 :                         len = stub->uncompressed_filesize;
    4038              64 :                         goto carry_on;
    4039                 :                 } else {
    4040               6 :                         RETURN_STRINGL("", 0, 1);
    4041                 :                 }
    4042                 :         }
    4043              67 :         len = phar_obj->arc.archive->halt_offset;
    4044                 : 
    4045             134 :         if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) {
    4046              67 :                 fp = phar_obj->arc.archive->fp;
    4047                 :         } else {
    4048               0 :                 fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL);
    4049                 :         }
    4050                 : 
    4051              67 :         if (!fp)  {
    4052               0 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4053                 :                         "Unable to read stub");
    4054               0 :                 return;
    4055                 :         }
    4056                 : 
    4057              67 :         php_stream_rewind(fp);
    4058             131 : carry_on:
    4059             131 :         buf = safe_emalloc(len, 1, 1);
    4060                 : 
    4061             131 :         if (len != php_stream_read(fp, buf, len)) {
    4062               0 :                 if (fp != phar_obj->arc.archive->fp) {
    4063               0 :                         php_stream_close(fp);
    4064                 :                 }
    4065               0 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4066                 :                         "Unable to read stub");
    4067               0 :                 efree(buf);
    4068               0 :                 return;
    4069                 :         }
    4070                 : 
    4071             131 :         if (filter) {
    4072               0 :                 php_stream_filter_flush(filter, 1);
    4073               0 :                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
    4074                 :         }
    4075                 : 
    4076             131 :         if (fp != phar_obj->arc.archive->fp) {
    4077               0 :                 php_stream_close(fp);
    4078                 :         }
    4079                 : 
    4080             131 :         buf[len] = '\0';
    4081             131 :         RETURN_STRINGL(buf, len, 0);
    4082                 : }
    4083                 : /* }}}*/
    4084                 : 
    4085                 : /* {{{ proto int Phar::hasMetaData()
    4086                 :  * Returns TRUE if the phar has global metadata, FALSE otherwise.
    4087                 :  */
    4088                 : PHP_METHOD(Phar, hasMetadata)
    4089               1 : {
    4090               1 :         PHAR_ARCHIVE_OBJECT();
    4091                 : 
    4092               1 :         RETURN_BOOL(phar_obj->arc.archive->metadata != NULL);
    4093                 : }
    4094                 : /* }}} */
    4095                 : 
    4096                 : /* {{{ proto int Phar::getMetaData()
    4097                 :  * Returns the global metadata of the phar
    4098                 :  */
    4099                 : PHP_METHOD(Phar, getMetadata)
    4100              17 : {
    4101              17 :         PHAR_ARCHIVE_OBJECT();
    4102                 : 
    4103              17 :         if (phar_obj->arc.archive->metadata) {
    4104              12 :                 if (phar_obj->arc.archive->is_persistent) {
    4105                 :                         zval *ret;
    4106               1 :                         char *buf = estrndup((char *) phar_obj->arc.archive->metadata, phar_obj->arc.archive->metadata_len);
    4107                 :                         /* assume success, we would have failed before */
    4108               1 :                         phar_parse_metadata(&buf, &ret, phar_obj->arc.archive->metadata_len TSRMLS_CC);
    4109               1 :                         efree(buf);
    4110               1 :                         RETURN_ZVAL(ret, 0, 1);
    4111                 :                 }
    4112              11 :                 RETURN_ZVAL(phar_obj->arc.archive->metadata, 1, 0);
    4113                 :         }
    4114                 : }
    4115                 : /* }}} */
    4116                 : 
    4117                 : /* {{{ proto int Phar::setMetaData(mixed $metadata)
    4118                 :  * Sets the global metadata of the phar
    4119                 :  */
    4120                 : PHP_METHOD(Phar, setMetadata)
    4121              10 : {
    4122                 :         char *error;
    4123                 :         zval *metadata;
    4124                 : 
    4125              10 :         PHAR_ARCHIVE_OBJECT();
    4126                 : 
    4127              10 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    4128               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
    4129               1 :                 return;
    4130                 :         }
    4131                 : 
    4132               9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
    4133               1 :                 return;
    4134                 :         }
    4135                 : 
    4136               8 :         if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
    4137               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
    4138               0 :                 return;
    4139                 :         }
    4140               8 :         if (phar_obj->arc.archive->metadata) {
    4141               1 :                 zval_ptr_dtor(&phar_obj->arc.archive->metadata);
    4142               1 :                 phar_obj->arc.archive->metadata = NULL;
    4143                 :         }
    4144                 : 
    4145               8 :         MAKE_STD_ZVAL(phar_obj->arc.archive->metadata);
    4146               8 :         ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0);
    4147               8 :         phar_obj->arc.archive->is_modified = 1;
    4148               8 :         phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    4149                 : 
    4150               8 :         if (error) {
    4151               0 :                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    4152               0 :                 efree(error);
    4153                 :         }
    4154                 : }
    4155                 : /* }}} */
    4156                 : 
    4157                 : /* {{{ proto int Phar::delMetadata()
    4158                 :  * Deletes the global metadata of the phar
    4159                 :  */
    4160                 : PHP_METHOD(Phar, delMetadata)
    4161               3 : {
    4162                 :         char *error;
    4163                 : 
    4164               3 :         PHAR_ARCHIVE_OBJECT();
    4165                 : 
    4166               3 :         if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
    4167               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
    4168               1 :                 return;
    4169                 :         }
    4170                 : 
    4171               2 :         if (phar_obj->arc.archive->metadata) {
    4172               1 :                 zval_ptr_dtor(&phar_obj->arc.archive->metadata);
    4173               1 :                 phar_obj->arc.archive->metadata = NULL;
    4174               1 :                 phar_obj->arc.archive->is_modified = 1;
    4175               1 :                 phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
    4176                 : 
    4177               1 :                 if (error) {
    4178               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
    4179               0 :                         efree(error);
    4180               0 :                         RETURN_FALSE;
    4181                 :                 } else {
    4182               1 :                         RETURN_TRUE;
    4183                 :                 }
    4184                 : 
    4185                 :         } else {
    4186               1 :                 RETURN_TRUE;
    4187                 :         }
    4188                 : }
    4189                 : /* }}} */
    4190                 : #if (PHP_MAJOR_VERSION < 6)
    4191                 : #define OPENBASEDIR_CHECKPATH(filename) \
    4192                 :         (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
    4193                 : #else
    4194                 : #define OPENBASEDIR_CHECKPATH(filename) \
    4195                 :         php_check_open_basedir(filename TSRMLS_CC)
    4196                 : #endif
    4197                 : 
    4198                 : static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC) /* {{{ */
    4199              21 : {
    4200                 :         php_stream_statbuf ssb;
    4201                 :         int len;
    4202                 :         php_stream *fp;
    4203                 :         char *fullpath, *slash;
    4204                 :         mode_t mode;
    4205                 : 
    4206              21 :         if (entry->is_mounted) {
    4207                 :                 /* silently ignore mounted entries */
    4208               4 :                 return SUCCESS;
    4209                 :         }
    4210                 : 
    4211              17 :         if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) {
    4212               0 :                 return SUCCESS;
    4213                 :         }
    4214                 : 
    4215              17 :         len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename);
    4216                 : 
    4217              17 :         if (len >= MAXPATHLEN) {
    4218                 :                 char *tmp;
    4219                 :                 /* truncate for error message */
    4220               1 :                 fullpath[50] = '\0';
    4221               1 :                 if (entry->filename_len > 50) {
    4222               1 :                         tmp = estrndup(entry->filename, 50);
    4223               1 :                         spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, fullpath);
    4224               1 :                         efree(tmp);
    4225                 :                 } else {
    4226               0 :                         spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath);
    4227                 :                 }
    4228               1 :                 efree(fullpath);
    4229               1 :                 return FAILURE;
    4230                 :         }
    4231                 : 
    4232              16 :         if (!len) {
    4233               0 :                 spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
    4234               0 :                 efree(fullpath);
    4235               0 :                 return FAILURE;
    4236                 :         }
    4237                 : 
    4238              16 :         if (OPENBASEDIR_CHECKPATH(fullpath)) {
    4239               0 :                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath);
    4240               0 :                 efree(fullpath);
    4241               0 :                 return FAILURE;
    4242                 :         }
    4243                 : 
    4244                 :         /* let see if the path already exists */
    4245              16 :         if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) {
    4246               1 :                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath);
    4247               1 :                 efree(fullpath);
    4248               1 :                 return FAILURE;
    4249                 :         }
    4250                 : 
    4251                 :         /* perform dirname */
    4252              15 :         slash = zend_memrchr(entry->filename, '/', entry->filename_len);
    4253                 : 
    4254              15 :         if (slash) {
    4255               6 :                 fullpath[dest_len + (slash - entry->filename) + 1] = '\0';
    4256                 :         } else {
    4257               9 :                 fullpath[dest_len] = '\0';
    4258                 :         }
    4259                 : 
    4260              15 :         if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
    4261               6 :                 if (entry->is_dir) {
    4262               3 :                         if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
    4263               0 :                                 spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
    4264               0 :                                 efree(fullpath);
    4265               0 :                                 return FAILURE;
    4266                 :                         }
    4267                 :                 } else {
    4268               3 :                         if (!php_stream_mkdir(fullpath, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
    4269               0 :                                 spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
    4270               0 :                                 efree(fullpath);
    4271               0 :                                 return FAILURE;
    4272                 :                         }
    4273                 :                 }
    4274                 :         }
    4275                 : 
    4276              15 :         if (slash) {
    4277               6 :                 fullpath[dest_len + (slash - entry->filename) + 1] = '/';
    4278                 :         } else {
    4279               9 :                 fullpath[dest_len] = '/';
    4280                 :         }
    4281                 : 
    4282                 :         /* it is a standalone directory, job done */
    4283              15 :         if (entry->is_dir) {
    4284               3 :                 efree(fullpath);
    4285               3 :                 return SUCCESS;
    4286                 :         }
    4287                 : 
    4288              12 :         fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
    4289                 : 
    4290              12 :         if (!fp) {
    4291               0 :                 spprintf(error, 4096, "Cannot extract \"%s\", could not open for writing \"%s\"", entry->filename, fullpath);
    4292               0 :                 efree(fullpath);
    4293               0 :                 return FAILURE;
    4294                 :         }
    4295                 : 
    4296              12 :         if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
    4297               0 :                 if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
    4298               0 :                         if (error) {
    4299               0 :                                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
    4300                 :                         } else {
    4301               0 :                                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", entry->filename, fullpath);
    4302                 :                         }
    4303               0 :                         efree(fullpath);
    4304               0 :                         php_stream_close(fp);
    4305               0 :                         return FAILURE;
    4306                 :                 }
    4307                 :         }
    4308                 : 
    4309              12 :         if (FAILURE == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
    4310               0 :                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to seek internal file pointer", entry->filename, fullpath);
    4311               0 :                 efree(fullpath);
    4312               0 :                 php_stream_close(fp);
    4313               0 :                 return FAILURE;
    4314                 :         }
    4315                 : 
    4316              12 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp, entry->uncompressed_filesize, NULL)) {
    4317               0 :                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", copying contents failed", entry->filename, fullpath);
    4318               0 :                 efree(fullpath);
    4319               0 :                 php_stream_close(fp);
    4320               0 :                 return FAILURE;
    4321                 :         }
    4322                 : 
    4323              12 :         php_stream_close(fp);
    4324              12 :         mode = (mode_t) entry->flags & PHAR_ENT_PERM_MASK;
    4325                 : 
    4326              12 :         if (FAILURE == VCWD_CHMOD(fullpath, mode)) {
    4327               0 :                 spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", setting file permissions failed", entry->filename, fullpath);
    4328               0 :                 efree(fullpath);
    4329               0 :                 return FAILURE;
    4330                 :         }
    4331                 : 
    4332              12 :         efree(fullpath);
    4333              12 :         return SUCCESS;
    4334                 : }
    4335                 : /* }}} */
    4336                 : 
    4337                 : /* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
    4338                 :  * Extract one or more file from a phar archive, optionally overwriting existing files
    4339                 :  */
    4340                 : PHP_METHOD(Phar, extractTo)
    4341              18 : {
    4342              18 :         char *error = NULL;
    4343                 :         php_stream *fp;
    4344                 :         php_stream_statbuf ssb;
    4345                 :         phar_entry_info *entry;
    4346                 :         char *pathto, *filename, *actual;
    4347                 :         int pathto_len, filename_len;
    4348                 :         int ret, i;
    4349                 :         int nelems;
    4350              18 :         zval *zval_files = NULL;
    4351              18 :         zend_bool overwrite = 0;
    4352                 : 
    4353              18 :         PHAR_ARCHIVE_OBJECT();
    4354                 : 
    4355              18 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) {
    4356               1 :                 return;
    4357                 :         }
    4358                 : 
    4359              17 :         fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
    4360                 : 
    4361              17 :         if (!fp) {
    4362               1 :                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
    4363                 :                         "Invalid argument, %s cannot be found", phar_obj->arc.archive->fname);
    4364               1 :                 return;
    4365                 :         }
    4366                 : 
    4367              16 :         efree(actual);
    4368              16 :         php_stream_close(fp);
    4369                 : 
    4370              16 :         if (pathto_len < 1) {
    4371               1 :                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
    4372                 :                         "Invalid argument, extraction path must be non-zero length");
    4373               1 :                 return;
    4374                 :         }
    4375                 : 
    4376              15 :         if (pathto_len >= MAXPATHLEN) {
    4377               1 :                 char *tmp = estrndup(pathto, 50);
    4378                 :                 /* truncate for error message */
    4379               1 :                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Cannot extract to \"%s...\", destination directory is too long for filesystem", tmp);
    4380               1 :                 efree(tmp);
    4381               1 :                 return;
    4382                 :         }
    4383                 : 
    4384              14 :         if (php_stream_stat_path(pathto, &ssb) < 0) {
    4385               7 :                 ret = php_stream_mkdir(pathto, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL);
    4386               7 :                 if (!ret) {
    4387               0 :                         zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4388                 :                                 "Unable to create path \"%s\" for extraction", pathto);
    4389               0 :                         return;
    4390                 :                 }
    4391               7 :         } else if (!(ssb.sb.st_mode & S_IFDIR)) {
    4392               1 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4393                 :                         "Unable to use path \"%s\" for extraction, it is a file, must be a directory", pathto);
    4394               1 :                 return;
    4395                 :         }
    4396                 : 
    4397              13 :         if (zval_files) {
    4398              10 :                 switch (Z_TYPE_P(zval_files)) {
    4399                 :                         case IS_NULL:
    4400               0 :                                 goto all_files;
    4401                 : #if PHP_VERSION_ID >= 60000
    4402                 :                         case IS_UNICODE:
    4403                 :                                 zval_unicode_to_string(zval_files TSRMLS_CC);
    4404                 :                                 /* break intentionally omitted */
    4405                 : #endif
    4406                 :                         case IS_STRING:
    4407               7 :                                 filename = Z_STRVAL_P(zval_files);
    4408               7 :                                 filename_len = Z_STRLEN_P(zval_files);
    4409                 :                                 break;
    4410                 :                         case IS_ARRAY:
    4411               2 :                                 nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files));
    4412               2 :                                 if (nelems == 0 ) {
    4413               0 :                                         RETURN_FALSE;
    4414                 :                                 }
    4415               4 :                                 for (i = 0; i < nelems; i++) {
    4416                 :                                         zval **zval_file;
    4417               3 :                                         if (zend_hash_index_find(Z_ARRVAL_P(zval_files), i, (void **) &zval_file) == SUCCESS) {
    4418               3 :                                                 switch (Z_TYPE_PP(zval_file)) {
    4419                 : #if PHP_VERSION_ID >= 60000
    4420                 :                                                         case IS_UNICODE:
    4421                 :                                                                 zval_unicode_to_string(*(zval_file) TSRMLS_CC);
    4422                 :                                                                 /* break intentionally omitted */
    4423                 : #endif
    4424                 :                                                         case IS_STRING:
    4425                 :                                                                 break;
    4426                 :                                                         default:
    4427               1 :                                                                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
    4428                 :                                                                         "Invalid argument, array of filenames to extract contains non-string value");
    4429               1 :                                                                 return;
    4430                 :                                                 }
    4431               2 :                                                 if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, Z_STRVAL_PP(zval_file), Z_STRLEN_PP(zval_file), (void **)&entry)) {
    4432               0 :                                                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
    4433                 :                                                                 "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_PP(zval_file), phar_obj->arc.archive->fname);
    4434                 :                                                 }
    4435               2 :                                                 if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
    4436               0 :                                                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
    4437                 :                                                                 "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
    4438               0 :                                                         efree(error);
    4439               0 :                                                         return;
    4440                 :                                                 }
    4441                 :                                         }
    4442                 :                                 }
    4443               1 :                                 RETURN_TRUE;
    4444                 :                         default:
    4445               1 :                                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
    4446                 :                                         "Invalid argument, expected a filename (string) or array of filenames");
    4447               1 :                                 return;
    4448                 :                 }
    4449                 : 
    4450               7 :                 if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, filename, filename_len, (void **)&entry)) {
    4451               0 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
    4452                 :                                 "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->arc.archive->fname);
    4453               0 :                         return;
    4454                 :                 }
    4455                 : 
    4456               7 :                 if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
    4457               2 :                         zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
    4458                 :                                 "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
    4459               2 :                         efree(error);
    4460               2 :                         return;
    4461                 :                 }
    4462                 :         } else {
    4463                 :                 phar_archive_data *phar;
    4464               3 : all_files:
    4465               3 :                 phar = phar_obj->arc.archive;
    4466                 :                 /* Extract all files */
    4467               3 :                 if (!zend_hash_num_elements(&(phar->manifest))) {
    4468               0 :                         RETURN_TRUE;
    4469                 :                 }
    4470                 : 
    4471               3 :                 for (zend_hash_internal_pointer_reset(&phar->manifest);
    4472              18 :                 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
    4473              12 :                 zend_hash_move_forward(&phar->manifest)) {
    4474                 : 
    4475              12 :                         if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
    4476               0 :                                 continue;
    4477                 :                         }
    4478                 : 
    4479              12 :                         if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
    4480               0 :                                 zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
    4481                 :                                         "Extraction from phar \"%s\" failed: %s", phar->fname, error);
    4482               0 :                                 efree(error);
    4483               0 :                                 return;
    4484                 :                         }
    4485                 :                 }
    4486                 :         }
    4487               8 :         RETURN_TRUE;
    4488                 : }
    4489                 : /* }}} */
    4490                 : 
    4491                 : 
    4492                 : /* {{{ proto void PharFileInfo::__construct(string entry)
    4493                 :  * Construct a Phar entry object
    4494                 :  */
    4495                 : PHP_METHOD(PharFileInfo, __construct)
    4496             398 : {
    4497                 :         char *fname, *arch, *entry, *error;
    4498                 :         int fname_len, arch_len, entry_len;
    4499                 :         phar_entry_object *entry_obj;
    4500                 :         phar_entry_info *entry_info;
    4501                 :         phar_archive_data *phar_data;
    4502             398 :         zval *zobj = getThis(), arg1;
    4503                 : 
    4504             398 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
    4505               1 :                 return;
    4506                 :         }
    4507                 : 
    4508             397 :         entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    4509                 : 
    4510             397 :         if (entry_obj->ent.entry) {
    4511               1 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
    4512               1 :                 return;
    4513                 :         }
    4514                 : 
    4515             396 :         if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC) == FAILURE) {
    4516               1 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4517                 :                         "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
    4518               1 :                 return;
    4519                 :         }
    4520                 : 
    4521             395 :         if (phar_open_from_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
    4522               1 :                 efree(arch);
    4523               1 :                 efree(entry);
    4524               1 :                 if (error) {
    4525               1 :                         zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4526                 :                                 "Cannot open phar file '%s': %s", fname, error);
    4527               1 :                         efree(error);
    4528                 :                 } else {
    4529               0 :                         zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4530                 :                                 "Cannot open phar file '%s'", fname);
    4531                 :                 }
    4532               1 :                 return;
    4533                 :         }
    4534                 : 
    4535             394 :         if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error, 1 TSRMLS_CC)) == NULL) {
    4536               1 :                 zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
    4537                 :                         "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error ? ", " : "", error ? error : "");
    4538               1 :                 efree(arch);
    4539               1 :                 efree(entry);
    4540               1 :                 return;
    4541                 :         }
    4542                 : 
    4543             393 :         efree(arch);
    4544             393 :         efree(entry);
    4545                 : 
    4546             393 :         entry_obj->ent.entry = entry_info;
    4547                 : 
    4548             393 :         INIT_PZVAL(&arg1);
    4549             393 :         ZVAL_STRINGL(&arg1, fname, fname_len, 0);
    4550                 : 
    4551             393 :         zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), 
    4552                 :                 &spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1);
    4553                 : }
    4554                 : /* }}} */
    4555                 : 
    4556                 : #define PHAR_ENTRY_OBJECT() \
    4557                 :         phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
    4558                 :         if (!entry_obj->ent.entry) { \
    4559                 :                 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
    4560                 :                         "Cannot call method on an uni