Back to index

php5  5.3.10
phar_object.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | phar php single-file executable PHP extension                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 2005-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt.                                 |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Gregory Beaver <cellog@php.net>                             |
00016   |          Marcus Boerger <helly@php.net>                              |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: phar_object.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "phar_internal.h"
00023 #include "func_interceptors.h"
00024 
00025 static zend_class_entry *phar_ce_archive;
00026 static zend_class_entry *phar_ce_data;
00027 static zend_class_entry *phar_ce_PharException;
00028 
00029 #if HAVE_SPL
00030 static zend_class_entry *phar_ce_entry;
00031 #endif
00032 
00033 #if PHP_MAJOR_VERSION > 5 || ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3))
00034 # define PHAR_ARG_INFO
00035 #else
00036 # define PHAR_ARG_INFO static
00037 #endif
00038 
00039 static int phar_file_type(HashTable *mimes, char *file, char **mime_type TSRMLS_DC) /* {{{ */
00040 {
00041        char *ext;
00042        phar_mime_type *mime;
00043        ext = strrchr(file, '.');
00044        if (!ext) {
00045               *mime_type = "text/plain";
00046               /* no file extension = assume text/plain */
00047               return PHAR_MIME_OTHER;
00048        }
00049        ++ext;
00050        if (SUCCESS != zend_hash_find(mimes, ext, strlen(ext), (void **) &mime)) {
00051               *mime_type = "application/octet-stream";
00052               return PHAR_MIME_OTHER;
00053        }
00054        *mime_type = mime->mime;
00055        return mime->type;
00056 }
00057 /* }}} */
00058 
00059 static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int request_uri_len TSRMLS_DC) /* {{{ */
00060 {
00061 #if PHP_MAJOR_VERSION >= 6
00062        int is_unicode = 0;
00063 #endif
00064        HashTable *_SERVER;
00065        zval **stuff;
00066        char *path_info;
00067        int basename_len = strlen(basename);
00068        int code;
00069        zval *temp;
00070 
00071        /* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
00072        if (!PG(http_globals)[TRACK_VARS_SERVER]) {
00073               return;
00074        }
00075 
00076        _SERVER = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
00077 
00078        /* PATH_INFO and PATH_TRANSLATED should always be munged */
00079 #if PHP_MAJOR_VERSION >= 6
00080        if (phar_find_key(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff TSRMLS_CC)) {
00081               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00082                      is_unicode = 1;
00083                      zval_unicode_to_string(*stuff TSRMLS_CC);
00084               } else {
00085                      is_unicode = 0;
00086               }
00087 #else
00088        if (SUCCESS == zend_hash_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
00089 #endif
00090 
00091               path_info = Z_STRVAL_PP(stuff);
00092               code = Z_STRLEN_PP(stuff);
00093 
00094               if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) {
00095                      ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1);
00096 
00097                      MAKE_STD_ZVAL(temp);
00098                      ZVAL_STRINGL(temp, path_info, code, 0);
00099 #if PHP_MAJOR_VERSION >= 6
00100                      if (is_unicode) {
00101                             zval_string_to_unicode(*stuff TSRMLS_CC);
00102                      }
00103 #endif
00104                      zend_hash_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO"), &temp, sizeof(zval **), NULL);
00105               }
00106        }
00107 
00108 #if PHP_MAJOR_VERSION >= 6
00109        if (phar_find_key(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff TSRMLS_CC)) {
00110               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00111                      is_unicode = 1;
00112                      zval_unicode_to_string(*stuff TSRMLS_CC);
00113               } else {
00114                      is_unicode = 0;
00115               }
00116 #else
00117        if (SUCCESS == zend_hash_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
00118 #endif
00119 
00120               path_info = Z_STRVAL_PP(stuff);
00121               code = Z_STRLEN_PP(stuff);
00122               Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
00123 
00124               MAKE_STD_ZVAL(temp);
00125               ZVAL_STRINGL(temp, path_info, code, 0);
00126 #if PHP_MAJOR_VERSION >= 6
00127               if (is_unicode) {
00128                      zval_string_to_unicode(*stuff TSRMLS_CC);
00129               }
00130 #endif
00131               zend_hash_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED"), (void *) &temp, sizeof(zval **), NULL);
00132        }
00133 
00134        if (!PHAR_GLOBALS->phar_SERVER_mung_list) {
00135               return;
00136        }
00137 
00138        if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_REQUEST_URI) {
00139 #if PHP_MAJOR_VERSION >= 6
00140               if (phar_find_key(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff TSRMLS_CC)) {
00141               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00142                      is_unicode = 1;
00143                      zval_unicode_to_string(*stuff TSRMLS_CC);
00144               } else {
00145                      is_unicode = 0;
00146               }
00147 #else
00148               if (SUCCESS == zend_hash_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
00149 #endif
00150 
00151                      path_info = Z_STRVAL_PP(stuff);
00152                      code = Z_STRLEN_PP(stuff);
00153 
00154                      if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
00155                             ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
00156 
00157                             MAKE_STD_ZVAL(temp);
00158                             ZVAL_STRINGL(temp, path_info, code, 0);
00159 #if PHP_MAJOR_VERSION >= 6
00160                             if (is_unicode) {
00161                                    zval_string_to_unicode(*stuff TSRMLS_CC);
00162                             }
00163 #endif
00164                             zend_hash_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI"), (void *) &temp, sizeof(zval **), NULL);
00165                      }
00166               }
00167        }
00168 
00169        if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_PHP_SELF) {
00170 #if PHP_MAJOR_VERSION >= 6
00171               if (phar_find_key(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff TSRMLS_CC)) {
00172               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00173                      is_unicode = 1;
00174                      zval_unicode_to_string(*stuff TSRMLS_CC);
00175               } else {
00176                      is_unicode = 0;
00177               }
00178 #else
00179               if (SUCCESS == zend_hash_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
00180 #endif
00181 
00182                      path_info = Z_STRVAL_PP(stuff);
00183                      code = Z_STRLEN_PP(stuff);
00184 
00185                      if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
00186                             ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
00187 
00188                             MAKE_STD_ZVAL(temp);
00189                             ZVAL_STRINGL(temp, path_info, code, 0);
00190 #if PHP_MAJOR_VERSION >= 6
00191                             if (is_unicode) {
00192                                    zval_string_to_unicode(*stuff TSRMLS_CC);
00193                             }
00194 #endif
00195                             zend_hash_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF"), (void *) &temp, sizeof(zval **), NULL);
00196                      }
00197               }
00198        }
00199 
00200        if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_NAME) {
00201 #if PHP_MAJOR_VERSION >= 6
00202               if (phar_find_key(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff TSRMLS_CC)) {
00203               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00204                      is_unicode = 1;
00205                      zval_unicode_to_string(*stuff TSRMLS_CC);
00206               } else {
00207                      is_unicode = 0;
00208               }
00209 #else
00210               if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
00211 #endif
00212 
00213                      path_info = Z_STRVAL_PP(stuff);
00214                      code = Z_STRLEN_PP(stuff);
00215                      ZVAL_STRINGL(*stuff, entry, entry_len, 1);
00216 
00217                      MAKE_STD_ZVAL(temp);
00218                      ZVAL_STRINGL(temp, path_info, code, 0);
00219 #if PHP_MAJOR_VERSION >= 6
00220                      if (is_unicode) {
00221                             zval_string_to_unicode(*stuff TSRMLS_CC);
00222                      }
00223 #endif
00224                      zend_hash_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME"), (void *) &temp, sizeof(zval **), NULL);
00225               }
00226        }
00227 
00228        if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_FILENAME) {
00229 #if PHP_MAJOR_VERSION >= 6
00230               if (phar_find_key(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff TSRMLS_CC)) {
00231               if (Z_TYPE_PP(stuff) == IS_UNICODE) {
00232                      is_unicode = 1;
00233                      zval_unicode_to_string(*stuff TSRMLS_CC);
00234               } else {
00235                      is_unicode = 0;
00236               }
00237 #else
00238               if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
00239 #endif
00240 
00241                      path_info = Z_STRVAL_PP(stuff);
00242                      code = Z_STRLEN_PP(stuff);
00243                      Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
00244 
00245                      MAKE_STD_ZVAL(temp);
00246                      ZVAL_STRINGL(temp, path_info, code, 0);
00247 #if PHP_MAJOR_VERSION >= 6
00248                      if (is_unicode) {
00249                             zval_string_to_unicode(*stuff TSRMLS_CC);
00250                      }
00251 #endif
00252                      zend_hash_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME"), (void *) &temp, sizeof(zval **), NULL);
00253               }
00254        }
00255 }
00256 /* }}} */
00257 
00258 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) /* {{{ */
00259 {
00260        char *name = NULL, buf[8192], *cwd;
00261        zend_syntax_highlighter_ini syntax_highlighter_ini;
00262        sapi_header_line ctr = {0};
00263        size_t got;
00264        int dummy = 1, name_len;
00265        zend_file_handle file_handle;
00266        zend_op_array *new_op_array;
00267        zval *result = NULL;
00268        php_stream *fp;
00269        off_t position;
00270 
00271        switch (code) {
00272               case PHAR_MIME_PHPS:
00273                      efree(basename);
00274                      /* highlight source */
00275                      if (entry[0] == '/') {
00276                             name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
00277                      } else {
00278                             name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
00279                      }
00280                      php_get_highlight_struct(&syntax_highlighter_ini);
00281 
00282                      highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
00283 
00284                      efree(name);
00285 #ifdef PHP_WIN32
00286                      efree(arch);
00287 #endif
00288                      zend_bailout();
00289               case PHAR_MIME_OTHER:
00290                      /* send headers, output file contents */
00291                      efree(basename);
00292                      ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
00293                      sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00294                      efree(ctr.line);
00295                      ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %u", info->uncompressed_filesize);
00296                      sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00297                      efree(ctr.line);
00298 
00299                      if (FAILURE == sapi_send_headers(TSRMLS_C)) {
00300                             zend_bailout();
00301                      }
00302 
00303                      /* prepare to output  */
00304                      fp = phar_get_efp(info, 1 TSRMLS_CC);
00305 
00306                      if (!fp) {
00307                             char *error;
00308                             if (!phar_open_jit(phar, info, &error TSRMLS_CC)) {
00309                                    if (error) {
00310                                           zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
00311                                           efree(error);
00312                                    }
00313                                    return -1;
00314                             }
00315                             fp = phar_get_efp(info, 1 TSRMLS_CC);
00316                      }
00317                      position = 0;
00318                      phar_seek_efp(info, 0, SEEK_SET, 0, 1 TSRMLS_CC);
00319 
00320                      do {
00321                             got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
00322                             if (got > 0) {
00323                                    PHPWRITE(buf, got);
00324                                    position += got;
00325                                    if (position == (off_t) info->uncompressed_filesize) {
00326                                           break;
00327                                    }
00328                             }
00329                      } while (1);
00330 
00331                      zend_bailout();
00332               case PHAR_MIME_PHP:
00333                      if (basename) {
00334                             phar_mung_server_vars(arch, entry, entry_len, basename, ru_len TSRMLS_CC);
00335                             efree(basename);
00336                      }
00337 
00338                      if (entry[0] == '/') {
00339                             name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
00340                      } else {
00341                             name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
00342                      }
00343 
00344                      file_handle.type = ZEND_HANDLE_FILENAME;
00345                      file_handle.handle.fd = 0;
00346                      file_handle.filename = name;
00347                      file_handle.opened_path = NULL;
00348                      file_handle.free_filename = 0;
00349 
00350                      PHAR_G(cwd) = NULL;
00351                      PHAR_G(cwd_len) = 0;
00352 
00353                      if (zend_hash_add(&EG(included_files), name, name_len+1, (void *)&dummy, sizeof(int), NULL) == SUCCESS) {
00354                             if ((cwd = zend_memrchr(entry, '/', entry_len))) {
00355                                    PHAR_G(cwd_init) = 1;
00356                                    if (entry == cwd) {
00357                                           /* root directory */
00358                                           PHAR_G(cwd_len) = 0;
00359                                           PHAR_G(cwd) = NULL;
00360                                    } else if (entry[0] == '/') {
00361                                           PHAR_G(cwd_len) = cwd - (entry + 1);
00362                                           PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
00363                                    } else {
00364                                           PHAR_G(cwd_len) = cwd - entry;
00365                                           PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
00366                                    }
00367                             }
00368 
00369                             new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
00370 
00371                             if (!new_op_array) {
00372                                    zend_hash_del(&EG(included_files), name, name_len+1);
00373                             }
00374 
00375                             zend_destroy_file_handle(&file_handle TSRMLS_CC);
00376 
00377                      } else {
00378                             efree(name);
00379                             new_op_array = NULL;
00380                      }
00381 #ifdef PHP_WIN32
00382                      efree(arch);
00383 #endif
00384                      if (new_op_array) {
00385                             EG(return_value_ptr_ptr) = &result;
00386                             EG(active_op_array) = new_op_array;
00387 
00388                             zend_try {
00389                                    zend_execute(new_op_array TSRMLS_CC);
00390                                    if (PHAR_G(cwd)) {
00391                                           efree(PHAR_G(cwd));
00392                                           PHAR_G(cwd) = NULL;
00393                                           PHAR_G(cwd_len) = 0;
00394                                    }
00395 
00396                                    PHAR_G(cwd_init) = 0;
00397                                    efree(name);
00398                                    destroy_op_array(new_op_array TSRMLS_CC);
00399                                    efree(new_op_array);
00400 
00401 
00402                                    if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
00403                                           zval_ptr_dtor(EG(return_value_ptr_ptr));
00404                                    }
00405                             } zend_catch {
00406                                    if (PHAR_G(cwd)) {
00407                                           efree(PHAR_G(cwd));
00408                                           PHAR_G(cwd) = NULL;
00409                                           PHAR_G(cwd_len) = 0;
00410                                    }
00411 
00412                                    PHAR_G(cwd_init) = 0;
00413                                    efree(name);
00414                             } zend_end_try();
00415 
00416                             zend_bailout();
00417                      }
00418 
00419                      return PHAR_MIME_PHP;
00420        }
00421        return -1;
00422 }
00423 /* }}} */
00424 
00425 static void phar_do_403(char *entry, int entry_len TSRMLS_DC) /* {{{ */
00426 {
00427        sapi_header_line ctr = {0};
00428 
00429        ctr.response_code = 403;
00430        ctr.line_len = sizeof("HTTP/1.0 403 Access Denied");
00431        ctr.line = "HTTP/1.0 403 Access Denied";
00432        sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00433        sapi_send_headers(TSRMLS_C);
00434        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);
00435        PHPWRITE(entry, entry_len);
00436        PHPWRITE(" Access Denied</h1>\n </body>\n</html>", sizeof(" Access Denied</h1>\n </body>\n</html>") - 1);
00437 }
00438 /* }}} */
00439 
00440 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) /* {{{ */
00441 {
00442        sapi_header_line ctr = {0};
00443        phar_entry_info      *info;
00444 
00445        if (phar && f404_len) {
00446               info = phar_get_entry_info(phar, f404, f404_len, NULL, 1 TSRMLS_CC);
00447 
00448               if (info) {
00449                      phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0 TSRMLS_CC);
00450                      return;
00451               }
00452        }
00453 
00454        ctr.response_code = 404;
00455        ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
00456        ctr.line = "HTTP/1.0 404 Not Found";
00457        sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00458        sapi_send_headers(TSRMLS_C);
00459        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);
00460        PHPWRITE(entry, entry_len);
00461        PHPWRITE(" Not Found</h1>\n </body>\n</html>",  sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
00462 }
00463 /* }}} */
00464 
00465 /* post-process REQUEST_URI and retrieve the actual request URI.  This is for
00466    cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
00467    which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
00468 static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len TSRMLS_DC) /* {{{ */
00469 {
00470        char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
00471        int e_len = *entry_len - 1, u_len = 0;
00472        phar_archive_data **pphar = NULL;
00473 
00474        /* we already know we can retrieve the phar if we reach here */
00475        zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
00476 
00477        if (!pphar && PHAR_G(manifest_cached)) {
00478               zend_hash_find(&cached_phars, fname, fname_len, (void **) &pphar);
00479        }
00480 
00481        do {
00482               if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
00483                      if (u) {
00484                             u[0] = '/';
00485                             *ru = estrndup(u, u_len+1);
00486                             ++u_len;
00487                             u[0] = '\0';
00488                      } else {
00489                             *ru = NULL;
00490                      }
00491                      *ru_len = u_len;
00492                      *entry_len = e_len + 1;
00493                      return;
00494               }
00495 
00496               if (u) {
00497                      u1 = strrchr(e, '/');
00498                      u[0] = '/';
00499                      saveu = u;
00500                      e_len += u_len + 1;
00501                      u = u1;
00502                      if (!u) {
00503                             return;
00504                      }
00505               } else {
00506                      u = strrchr(e, '/');
00507                      if (!u) {
00508                             if (saveu) {
00509                                    saveu[0] = '/';
00510                             }
00511                             return;
00512                      }
00513               }
00514 
00515               u[0] = '\0';
00516               u_len = strlen(u + 1);
00517               e_len -= u_len + 1;
00518 
00519               if (e_len < 0) {
00520                      if (saveu) {
00521                             saveu[0] = '/';
00522                      }
00523                      return;
00524               }
00525        } while (1);
00526 }
00527 /* }}} */
00528 
00529 /* {{{ proto void Phar::running([bool retphar = true])
00530  * return the name of the currently running phar archive.  If the optional parameter
00531  * is set to true, return the phar:// URL to the currently running phar
00532  */
00533 PHP_METHOD(Phar, running)
00534 {
00535        char *fname, *arch, *entry;
00536        int fname_len, arch_len, entry_len;
00537        zend_bool retphar = 1;
00538 
00539        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &retphar) == FAILURE) {
00540               return;
00541        }
00542 
00543        fname = zend_get_executed_filename(TSRMLS_C);
00544        fname_len = strlen(fname);
00545 
00546        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)) {
00547               efree(entry);
00548               if (retphar) {
00549                      RETVAL_STRINGL(fname, arch_len + 7, 1);
00550                      efree(arch);
00551                      return;
00552               } else {
00553                      RETURN_STRINGL(arch, arch_len, 0);
00554               }
00555        }
00556 
00557        RETURN_STRINGL("", 0, 1);
00558 }
00559 /* }}} */
00560 
00561 /* {{{ proto void Phar::mount(string pharpath, string externalfile)
00562  * mount an external file or path to a location within the phar.  This maps
00563  * an external file or directory to a location within the phar archive, allowing
00564  * reference to an external location as if it were within the phar archive.  This
00565  * is useful for writable temp files like databases
00566  */
00567 PHP_METHOD(Phar, mount)
00568 {
00569        char *fname, *arch = NULL, *entry = NULL, *path, *actual;
00570        int fname_len, arch_len, entry_len, path_len, actual_len;
00571        phar_archive_data **pphar;
00572 
00573        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) {
00574               return;
00575        }
00576 
00577        fname = zend_get_executed_filename(TSRMLS_C);
00578        fname_len = strlen(fname);
00579 
00580 #ifdef PHP_WIN32
00581        phar_unixify_path_separators(fname, fname_len);
00582 #endif
00583 
00584        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)) {
00585               efree(entry);
00586               entry = NULL;
00587 
00588               if (path_len > 7 && !memcmp(path, "phar://", 7)) {
00589                      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);
00590                      efree(arch);
00591                      return;
00592               }
00593 carry_on2:
00594               if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
00595                      if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, arch, arch_len, (void **)&pphar)) {
00596                             if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
00597                                    goto carry_on;
00598                             }
00599                      }
00600 
00601                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
00602 
00603                      if (arch) {
00604                             efree(arch);
00605                      }
00606                      return;
00607               }
00608 carry_on:
00609               if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) {
00610                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch);
00611                      if (path && path == entry) {
00612                             efree(entry);
00613                      }
00614 
00615                      if (arch) {
00616                             efree(arch);
00617                      }
00618 
00619                      return;
00620               }
00621 
00622               if (entry && path && path == entry) {
00623                      efree(entry);
00624               }
00625 
00626               if (arch) {
00627                      efree(arch);
00628               }
00629 
00630               return;
00631        } else if (PHAR_GLOBALS->phar_fname_map.arBuckets && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
00632               goto carry_on;
00633        } else if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, fname, fname_len, (void **)&pphar)) {
00634               if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
00635                      goto carry_on;
00636               }
00637 
00638               goto carry_on;
00639        } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
00640               path = entry;
00641               path_len = entry_len;
00642               goto carry_on2;
00643        }
00644 
00645        zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual);
00646 }
00647 /* }}} */
00648 
00649 /* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
00650  * mapPhar for web-based phars. Reads the currently executed file (a phar)
00651  * and registers its manifest. When executed in the CLI or CGI command-line sapi,
00652  * this works exactly like mapPhar().  When executed by a web-based sapi, this
00653  * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
00654  * intended internal file.
00655  */
00656 PHP_METHOD(Phar, webPhar)
00657 {
00658        zval *mimeoverride = NULL, *rewrite = NULL;
00659        char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
00660        int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0;
00661        char *fname, *basename, *path_info, *mime_type = NULL, *entry, *pt;
00662        int fname_len, entry_len, code, index_php_len = 0, not_cgi;
00663        phar_archive_data *phar = NULL;
00664        phar_entry_info *info = NULL;
00665 
00666        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) {
00667               return;
00668        }
00669 
00670        phar_request_initialize(TSRMLS_C);
00671        fname = zend_get_executed_filename(TSRMLS_C);
00672        fname_len = strlen(fname);
00673 
00674        if (phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) != SUCCESS) {
00675               if (error) {
00676                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
00677                      efree(error);
00678               }
00679               return;
00680        }
00681 
00682        /* retrieve requested file within phar */
00683        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")))) {
00684               return;
00685        }
00686 
00687 #ifdef PHP_WIN32
00688        fname = estrndup(fname, fname_len);
00689        phar_unixify_path_separators(fname, fname_len);
00690 #endif
00691        basename = zend_memrchr(fname, '/', fname_len);
00692 
00693        if (!basename) {
00694               basename = fname;
00695        } else {
00696               ++basename;
00697        }
00698 
00699        if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1))
00700               || (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) {
00701 
00702               if (PG(http_globals)[TRACK_VARS_SERVER]) {
00703                      HashTable *_server = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
00704                      zval **z_script_name, **z_path_info;
00705 
00706                      if (SUCCESS != zend_hash_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void**)&z_script_name) ||
00707                             IS_STRING != Z_TYPE_PP(z_script_name) ||
00708                             !strstr(Z_STRVAL_PP(z_script_name), basename)) {
00709                             return;
00710                      }
00711 
00712                      if (SUCCESS == zend_hash_find(_server, "PATH_INFO", sizeof("PATH_INFO"), (void**)&z_path_info) &&
00713                             IS_STRING == Z_TYPE_PP(z_path_info)) {
00714                             entry_len = Z_STRLEN_PP(z_path_info);
00715                             entry = estrndup(Z_STRVAL_PP(z_path_info), entry_len);
00716                             path_info = emalloc(Z_STRLEN_PP(z_script_name) + entry_len + 1);
00717                             memcpy(path_info, Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
00718                             memcpy(path_info + Z_STRLEN_PP(z_script_name), entry, entry_len + 1);
00719                             free_pathinfo = 1;
00720                      } else {
00721                             entry_len = 0;
00722                             entry = estrndup("", 0);
00723                             path_info = Z_STRVAL_PP(z_script_name);
00724                      }
00725 
00726                      pt = estrndup(Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
00727 
00728               } else {
00729                      char *testit;
00730 
00731                      testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
00732                      if (!(pt = strstr(testit, basename))) {
00733                             efree(testit);
00734                             return;
00735                      }
00736 
00737                      path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
00738 
00739                      if (path_info) {
00740                             entry = path_info;
00741                             entry_len = strlen(entry);
00742                             spprintf(&path_info, 0, "%s%s", testit, path_info);
00743                             free_pathinfo = 1;
00744                      } else {
00745                             path_info = testit;
00746                             free_pathinfo = 1;
00747                             entry = estrndup("", 0);
00748                             entry_len = 0;
00749                      }
00750 
00751                      pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
00752               }
00753               not_cgi = 0;
00754        } else {
00755               path_info = SG(request_info).request_uri;
00756 
00757               if (!(pt = strstr(path_info, basename))) {
00758                      /* this can happen with rewrite rules - and we have no idea what to do then, so return */
00759                      return;
00760               }
00761 
00762               entry_len = strlen(path_info);
00763               entry_len -= (pt - path_info) + (fname_len - (basename - fname));
00764               entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
00765 
00766               pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
00767               not_cgi = 1;
00768        }
00769 
00770        if (rewrite) {
00771               zend_fcall_info fci;
00772               zend_fcall_info_cache fcc;
00773               zval *params, *retval_ptr, **zp[1];
00774 
00775               MAKE_STD_ZVAL(params);
00776               ZVAL_STRINGL(params, entry, entry_len, 1);
00777               zp[0] = &params;
00778 
00779 #if PHP_VERSION_ID < 50300
00780               if (FAILURE == zend_fcall_info_init(rewrite, &fci, &fcc TSRMLS_CC)) {
00781 #else
00782               if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
00783 #endif
00784                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback");
00785 
00786                      if (free_pathinfo) {
00787                             efree(path_info);
00788                      }
00789 
00790                      return;
00791               }
00792 
00793               fci.param_count = 1;
00794               fci.params = zp;
00795 #if PHP_VERSION_ID < 50300
00796               ++(params->refcount);
00797 #else
00798               Z_ADDREF_P(params);
00799 #endif
00800               fci.retval_ptr_ptr = &retval_ptr;
00801 
00802               if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
00803                      if (!EG(exception)) {
00804                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback");
00805                      }
00806 
00807                      if (free_pathinfo) {
00808                             efree(path_info);
00809                      }
00810 
00811                      return;
00812               }
00813 
00814               if (!fci.retval_ptr_ptr || !retval_ptr) {
00815                      if (free_pathinfo) {
00816                             efree(path_info);
00817                      }
00818                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
00819                      return;
00820               }
00821 
00822               switch (Z_TYPE_P(retval_ptr)) {
00823 #if PHP_VERSION_ID >= 60000
00824                      case IS_UNICODE:
00825                             zval_unicode_to_string(retval_ptr TSRMLS_CC);
00826                             /* break intentionally omitted */
00827 #endif
00828                      case IS_STRING:
00829                             efree(entry);
00830 
00831                             if (fci.retval_ptr_ptr != &retval_ptr) {
00832                                    entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr));
00833                                    entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr);
00834                             } else {
00835                                    entry = Z_STRVAL_P(retval_ptr);
00836                                    entry_len = Z_STRLEN_P(retval_ptr);
00837                             }
00838 
00839                             break;
00840                      case IS_BOOL:
00841                             phar_do_403(entry, entry_len TSRMLS_CC);
00842 
00843                             if (free_pathinfo) {
00844                                    efree(path_info);
00845                             }
00846 
00847                             zend_bailout();
00848                             return;
00849                      default:
00850                             efree(retval_ptr);
00851 
00852                             if (free_pathinfo) {
00853                                    efree(path_info);
00854                             }
00855 
00856                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
00857                             return;
00858               }
00859        }
00860 
00861        if (entry_len) {
00862               phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC);
00863        }
00864 
00865        if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
00866               efree(entry);
00867               /* direct request */
00868               if (index_php_len) {
00869                      entry = index_php;
00870                      entry_len = index_php_len;
00871                      if (entry[0] != '/') {
00872                             spprintf(&entry, 0, "/%s", index_php);
00873                             ++entry_len;
00874                      }
00875               } else {
00876                      /* assume "index.php" is starting point */
00877                      entry = estrndup("/index.php", sizeof("/index.php"));
00878                      entry_len = sizeof("/index.php")-1;
00879               }
00880 
00881               if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
00882                      (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
00883                      phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
00884 
00885                      if (free_pathinfo) {
00886                             efree(path_info);
00887                      }
00888 
00889                      zend_bailout();
00890               } else {
00891                      char *tmp = NULL, sa = '\0';
00892                      sapi_header_line ctr = {0};
00893                      ctr.response_code = 301;
00894                      ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")+1;
00895                      ctr.line = "HTTP/1.1 301 Moved Permanently";
00896                      sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00897 
00898                      if (not_cgi) {
00899                             tmp = strstr(path_info, basename) + fname_len;
00900                             sa = *tmp;
00901                             *tmp = '\0';
00902                      }
00903 
00904                      ctr.response_code = 0;
00905 
00906                      if (path_info[strlen(path_info)-1] == '/') {
00907                             ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
00908                      } else {
00909                             ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
00910                      }
00911 
00912                      if (not_cgi) {
00913                             *tmp = sa;
00914                      }
00915 
00916                      if (free_pathinfo) {
00917                             efree(path_info);
00918                      }
00919 
00920                      sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00921                      sapi_send_headers(TSRMLS_C);
00922                      efree(ctr.line);
00923                      zend_bailout();
00924               }
00925        }
00926 
00927        if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
00928               (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
00929               phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
00930 #ifdef PHP_WIN32
00931               efree(fname);
00932 #endif
00933               zend_bailout();
00934        }
00935 
00936        if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
00937               char *ext = zend_memrchr(entry, '.', entry_len);
00938               zval **val;
00939 
00940               if (ext) {
00941                      ++ext;
00942 
00943 #if PHP_MAJOR_VERSION >= 6
00944                      if (phar_find_key(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val TSRMLS_CC)) {
00945 #else
00946                      if (SUCCESS == zend_hash_find(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val)) {
00947 #endif
00948                             switch (Z_TYPE_PP(val)) {
00949                                    case IS_LONG:
00950                                           if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
00951                                                  mime_type = "";
00952                                                  code = Z_LVAL_PP(val);
00953                                           } else {
00954                                                  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");
00955 #ifdef PHP_WIN32
00956                                                  efree(fname);
00957 #endif
00958                                                  RETURN_FALSE;
00959                                           }
00960                                           break;
00961 #if PHP_MAJOR_VERSION >= 6
00962                                    case IS_UNICODE:
00963                                           zval_unicode_to_string(*(val) TSRMLS_CC);
00964                                           /* break intentionally omitted */
00965 #endif
00966                                    case IS_STRING:
00967                                           mime_type = Z_STRVAL_PP(val);
00968                                           code = PHAR_MIME_OTHER;
00969                                           break;
00970                                    default:
00971                                           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");
00972 #ifdef PHP_WIN32
00973                                           efree(fname);
00974 #endif
00975                                           RETURN_FALSE;
00976                             }
00977                      }
00978               }
00979        }
00980 
00981        if (!mime_type) {
00982               code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type TSRMLS_CC);
00983        }
00984        ret = phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len TSRMLS_CC);
00985 }
00986 /* }}} */
00987 
00988 /* {{{ proto void Phar::mungServer(array munglist)
00989  * Defines a list of up to 4 $_SERVER variables that should be modified for execution
00990  * to mask the presence of the phar archive.  This should be used in conjunction with
00991  * Phar::webPhar(), and has no effect otherwise
00992  * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME
00993  */
00994 PHP_METHOD(Phar, mungServer)
00995 {
00996        zval *mungvalues;
00997 
00998        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) {
00999               return;
01000        }
01001 
01002        if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) {
01003               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");
01004               return;
01005        }
01006 
01007        if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
01008               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");
01009               return;
01010        }
01011 
01012        phar_request_initialize(TSRMLS_C);
01013 
01014        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))) {
01015               zval **data = NULL;
01016 #if PHP_MAJOR_VERSION >= 6
01017               zval *unicopy = NULL;
01018 #endif
01019 
01020               if (SUCCESS != zend_hash_get_current_data(Z_ARRVAL_P(mungvalues), (void **) &data)) {
01021                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "unable to retrieve array value in Phar::mungServer()");
01022                      return;
01023               }
01024 
01025 #if PHP_MAJOR_VERSION >= 6
01026               if (Z_TYPE_PP(data) == IS_UNICODE) {
01027                      MAKE_STD_ZVAL(unicopy);
01028                      *unicopy = **data;
01029                      zval_copy_ctor(unicopy);
01030                      INIT_PZVAL(unicopy);
01031                      zval_unicode_to_string(unicopy TSRMLS_CC);
01032                      data = &unicopy;
01033               }
01034 #endif
01035 
01036               if (Z_TYPE_PP(data) != IS_STRING) {
01037                      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");
01038                      return;
01039               }
01040 
01041               if (Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
01042                      PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_PHP_SELF;
01043               }
01044 
01045               if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) {
01046                      if (!strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
01047                             PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_REQUEST_URI;
01048                      }
01049                      if (!strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
01050                             PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_NAME;
01051                      }
01052               }
01053 
01054               if (Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
01055                      PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_FILENAME;
01056               }
01057 #if PHP_MAJOR_VERSION >= 6
01058               if (unicopy) {
01059                      zval_ptr_dtor(&unicopy);
01060               }
01061 #endif
01062        }
01063 }
01064 /* }}} */
01065 
01066 /* {{{ proto void Phar::interceptFileFuncs()
01067  * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
01068  * and return stat on files within the phar for relative paths
01069  *
01070  * Once called, this cannot be reversed, and continue until the end of the request.
01071  *
01072  * This allows legacy scripts to be pharred unmodified
01073  */
01074 PHP_METHOD(Phar, interceptFileFuncs)
01075 {
01076        if (zend_parse_parameters_none() == FAILURE) {
01077               return;
01078        }
01079        phar_intercept_functions(TSRMLS_C);
01080 }
01081 /* }}} */
01082 
01083 /* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]])
01084  * Return a stub that can be used to run a phar-based archive without the phar extension
01085  * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile
01086  * is the web startup filename, and also defaults to "index.php"
01087  */
01088 PHP_METHOD(Phar, createDefaultStub)
01089 {
01090        char *index = NULL, *webindex = NULL, *stub, *error;
01091        int index_len = 0, webindex_len = 0;
01092        size_t stub_len;
01093 
01094        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
01095               return;
01096        }
01097 
01098        stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
01099 
01100        if (error) {
01101               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
01102               efree(error);
01103               return;
01104        }
01105        RETURN_STRINGL(stub, stub_len, 0);
01106 }
01107 /* }}} */
01108 
01109 /* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
01110  * Reads the currently executed file (a phar) and registers its manifest */
01111 PHP_METHOD(Phar, mapPhar)
01112 {
01113        char *alias = NULL, *error;
01114        int alias_len = 0;
01115        long dataoffset = 0;
01116 
01117        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
01118               return;
01119        }
01120 
01121        phar_request_initialize(TSRMLS_C);
01122 
01123        RETVAL_BOOL(phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) == SUCCESS);
01124 
01125        if (error) {
01126               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
01127               efree(error);
01128        }
01129 } /* }}} */
01130 
01131 /* {{{ proto mixed Phar::loadPhar(string filename [, string alias])
01132  * Loads any phar archive with an alias */
01133 PHP_METHOD(Phar, loadPhar)
01134 {
01135        char *fname, *alias = NULL, *error;
01136        int fname_len, alias_len = 0;
01137 
01138        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) {
01139               return;
01140        }
01141 
01142        phar_request_initialize(TSRMLS_C);
01143 
01144        RETVAL_BOOL(phar_open_from_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS);
01145 
01146        if (error) {
01147               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
01148               efree(error);
01149        }
01150 } /* }}} */
01151 
01152 /* {{{ proto string Phar::apiVersion()
01153  * Returns the api version */
01154 PHP_METHOD(Phar, apiVersion)
01155 {
01156        if (zend_parse_parameters_none() == FAILURE) {
01157               return;
01158        }
01159        RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1, 1);
01160 }
01161 /* }}}*/
01162 
01163 /* {{{ proto bool Phar::canCompress([int method])
01164  * Returns whether phar extension supports compression using zlib/bzip2 */
01165 PHP_METHOD(Phar, canCompress)
01166 {
01167        long method = 0;
01168 
01169        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
01170               return;
01171        }
01172 
01173        phar_request_initialize(TSRMLS_C);
01174        switch (method) {
01175        case PHAR_ENT_COMPRESSED_GZ:
01176               if (PHAR_G(has_zlib)) {
01177                      RETURN_TRUE;
01178               } else {
01179                      RETURN_FALSE;
01180               }
01181        case PHAR_ENT_COMPRESSED_BZ2:
01182               if (PHAR_G(has_bz2)) {
01183                      RETURN_TRUE;
01184               } else {
01185                      RETURN_FALSE;
01186               }
01187        default:
01188               if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) {
01189                      RETURN_TRUE;
01190               } else {
01191                      RETURN_FALSE;
01192               }
01193        }
01194 }
01195 /* }}} */
01196 
01197 /* {{{ proto bool Phar::canWrite()
01198  * Returns whether phar extension supports writing and creating phars */
01199 PHP_METHOD(Phar, canWrite)
01200 {
01201        if (zend_parse_parameters_none() == FAILURE) {
01202               return;
01203        }
01204        RETURN_BOOL(!PHAR_G(readonly));
01205 }
01206 /* }}} */
01207 
01208 /* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
01209  * Returns whether the given filename is a valid phar filename */
01210 PHP_METHOD(Phar, isValidPharFilename)
01211 {
01212        char *fname;
01213        const char *ext_str;
01214        int fname_len, ext_len, is_executable;
01215        zend_bool executable = 1;
01216 
01217        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &fname, &fname_len, &executable) == FAILURE) {
01218               return;
01219        }
01220 
01221        is_executable = executable;
01222        RETVAL_BOOL(phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, is_executable, 2, 1 TSRMLS_CC) == SUCCESS);
01223 }
01224 /* }}} */
01225 
01226 #if HAVE_SPL
01227 
01230 static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
01231 {
01232        phar_archive_data *phar = (phar_archive_data *) object->oth;
01233 
01234        if (!phar->is_persistent) {
01235               phar_archive_delref(phar TSRMLS_CC);
01236        }
01237 
01238        object->oth = NULL;
01239 }
01240 /* }}} */
01241 
01245 static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC) /* {{{ */
01246 {
01247        phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
01248 
01249        if (!phar_data->is_persistent) {
01250               ++(phar_data->refcount);
01251        }
01252 }
01253 /* }}} */
01254 
01255 static spl_other_handler phar_spl_foreign_handler = {
01256        phar_spl_foreign_dtor,
01257        phar_spl_foreign_clone
01258 };
01259 #endif /* HAVE_SPL */
01260 
01261 /* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
01262  * Construct a Phar archive object
01263  *
01264  * proto void PharData::__construct(string fname [[, int flags [, string alias]], int file format = Phar::TAR])
01265  * Construct a PharData archive object
01266  *
01267  * This function is used as the constructor for both the Phar and PharData
01268  * classes, hence the two prototypes above.
01269  */
01270 PHP_METHOD(Phar, __construct)
01271 {
01272 #if !HAVE_SPL
01273        zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
01274 #else
01275        char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname;
01276        int fname_len, alias_len = 0, arch_len, entry_len, is_data;
01277 #if PHP_VERSION_ID < 50300
01278        long flags = 0;
01279 #else
01280        long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
01281 #endif
01282        long format = 0;
01283        phar_archive_object *phar_obj;
01284        phar_archive_data   *phar_data;
01285        zval *zobj = getThis(), arg1, arg2;
01286 
01287        phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01288 
01289        is_data = instanceof_function(Z_OBJCE_P(zobj), phar_ce_data TSRMLS_CC);
01290 
01291        if (is_data) {
01292               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!l", &fname, &fname_len, &flags, &alias, &alias_len, &format) == FAILURE) {
01293                      return;
01294               }
01295        } else {
01296               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) {
01297                      return;
01298               }
01299        }
01300 
01301        if (phar_obj->arc.archive) {
01302               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
01303               return;
01304        }
01305 
01306        save_fname = fname;
01307        if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2 TSRMLS_CC)) {
01308               /* use arch (the basename for the archive) for fname instead of fname */
01309               /* this allows support for RecursiveDirectoryIterator of subdirectories */
01310 #ifdef PHP_WIN32
01311               phar_unixify_path_separators(arch, arch_len);
01312 #endif
01313               fname = arch;
01314               fname_len = arch_len;
01315 #ifdef PHP_WIN32
01316        } else {
01317               arch = estrndup(fname, fname_len);
01318               arch_len = fname_len;
01319               fname = arch;
01320               phar_unixify_path_separators(arch, arch_len);
01321 #endif
01322        }
01323 
01324        if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
01325 
01326               if (fname == arch && fname != save_fname) {
01327                      efree(arch);
01328                      fname = save_fname;
01329               }
01330 
01331               if (entry) {
01332                      efree(entry);
01333               }
01334 
01335               if (error) {
01336                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
01337                             "%s", error);
01338                      efree(error);
01339               } else {
01340                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
01341                             "Phar creation or opening failed");
01342               }
01343 
01344               return;
01345        }
01346 
01347        if (is_data && phar_data->is_tar && phar_data->is_brandnew && format == PHAR_FORMAT_ZIP) {
01348               phar_data->is_zip = 1;
01349               phar_data->is_tar = 0;
01350        }
01351 
01352        if (fname == arch) {
01353               efree(arch);
01354               fname = save_fname;
01355        }
01356 
01357        if ((is_data && !phar_data->is_data) || (!is_data && phar_data->is_data)) {
01358               if (is_data) {
01359                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
01360                             "PharData class can only be used for non-executable tar and zip archives");
01361               } else {
01362                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
01363                             "Phar class can only be used for executable tar and zip archives");
01364               }
01365               efree(entry);
01366               return;
01367        }
01368 
01369        is_data = phar_data->is_data;
01370 
01371        if (!phar_data->is_persistent) {
01372               ++(phar_data->refcount);
01373        }
01374 
01375        phar_obj->arc.archive = phar_data;
01376        phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
01377 
01378        if (entry) {
01379               fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry);
01380               efree(entry);
01381        } else {
01382               fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
01383        }
01384 
01385        INIT_PZVAL(&arg1);
01386        ZVAL_STRINGL(&arg1, fname, fname_len, 0);
01387        INIT_PZVAL(&arg2);
01388        ZVAL_LONG(&arg2, flags);
01389 
01390        zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj), 
01391               &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
01392 
01393        if (!phar_data->is_persistent) {
01394               phar_obj->arc.archive->is_data = is_data;
01395        } else if (!EG(exception)) {
01396               /* register this guy so we can modify if necessary */
01397               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);
01398        }
01399 
01400        phar_obj->spl.info_class = phar_ce_entry;
01401        efree(fname);
01402 #endif /* HAVE_SPL */
01403 }
01404 /* }}} */
01405 
01406 /* {{{ proto array Phar::getSupportedSignatures()
01407  * Return array of supported signature types
01408  */
01409 PHP_METHOD(Phar, getSupportedSignatures)
01410 {
01411        if (zend_parse_parameters_none() == FAILURE) {
01412               return;
01413        }
01414        
01415        array_init(return_value);
01416 
01417        add_next_index_stringl(return_value, "MD5", 3, 1);
01418        add_next_index_stringl(return_value, "SHA-1", 5, 1);
01419 #ifdef PHAR_HASH_OK
01420        add_next_index_stringl(return_value, "SHA-256", 7, 1);
01421        add_next_index_stringl(return_value, "SHA-512", 7, 1);
01422 #endif
01423 #if PHAR_HAVE_OPENSSL
01424        add_next_index_stringl(return_value, "OpenSSL", 7, 1);
01425 #else
01426        if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
01427               add_next_index_stringl(return_value, "OpenSSL", 7, 1);
01428        }
01429 #endif
01430 }
01431 /* }}} */
01432 
01433 /* {{{ proto array Phar::getSupportedCompression()
01434  * Return array of supported comparession algorithms
01435  */
01436 PHP_METHOD(Phar, getSupportedCompression)
01437 {
01438        if (zend_parse_parameters_none() == FAILURE) {
01439               return;
01440        }
01441        
01442        array_init(return_value);
01443        phar_request_initialize(TSRMLS_C);
01444 
01445        if (PHAR_G(has_zlib)) {
01446               add_next_index_stringl(return_value, "GZ", 2, 1);
01447        }
01448 
01449        if (PHAR_G(has_bz2)) {
01450               add_next_index_stringl(return_value, "BZIP2", 5, 1);
01451        }
01452 }
01453 /* }}} */
01454 
01455 /* {{{ proto array Phar::unlinkArchive(string archive)
01456  * Completely remove a phar archive from memory and disk
01457  */
01458 PHP_METHOD(Phar, unlinkArchive)
01459 {
01460        char *fname, *error, *zname, *arch, *entry;
01461        int fname_len, zname_len, arch_len, entry_len;
01462        phar_archive_data *phar;
01463 
01464        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
01465               RETURN_FALSE;
01466        }
01467 
01468        if (!fname_len) {
01469               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"\"");
01470               return;
01471        }
01472 
01473        if (FAILURE == phar_open_from_filename(fname, fname_len, NULL, 0, REPORT_ERRORS, &phar, &error TSRMLS_CC)) {
01474               if (error) {
01475                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\": %s", fname, error);
01476                      efree(error);
01477               } else {
01478                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\"", fname);
01479               }
01480               return;
01481        }
01482 
01483        zname = zend_get_executed_filename(TSRMLS_C);
01484        zname_len = strlen(zname);
01485 
01486        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)) {
01487               if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
01488                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" cannot be unlinked from within itself", fname);
01489                      efree(arch);
01490                      efree(entry);
01491                      return;
01492               }
01493               efree(arch);
01494               efree(entry);
01495        }
01496 
01497        if (phar->is_persistent) {
01498               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
01499               return;
01500        }
01501 
01502        if (phar->refcount) {
01503               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);
01504               return;
01505        }
01506 
01507        fname = estrndup(phar->fname, phar->fname_len);
01508 
01509        /* invalidate phar cache */
01510        PHAR_G(last_phar) = NULL;
01511        PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
01512 
01513        phar_archive_delref(phar TSRMLS_CC);
01514        unlink(fname);
01515        efree(fname);
01516        RETURN_TRUE;
01517 }
01518 /* }}} */
01519 
01520 #if HAVE_SPL
01521 
01522 #define PHAR_ARCHIVE_OBJECT() \
01523        phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
01524        if (!phar_obj->arc.archive) { \
01525               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
01526                      "Cannot call method on an uninitialized Phar object"); \
01527               return; \
01528        }
01529 
01530 /* {{{ proto void Phar::__destruct()
01531  * if persistent, remove from the cache
01532  */
01533 PHP_METHOD(Phar, __destruct)
01534 {
01535        phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01536 
01537        if (phar_obj->arc.archive && phar_obj->arc.archive->is_persistent) {
01538               zend_hash_del(&PHAR_GLOBALS->phar_persist_map, (const char *) phar_obj->arc.archive, sizeof(phar_obj->arc.archive));
01539        }
01540 }
01541 /* }}} */
01542 
01543 struct _phar_t {
01544        phar_archive_object *p;
01545        zend_class_entry *c;
01546        char *b;
01547        uint l;
01548        zval *ret;
01549        int count;
01550        php_stream *fp;
01551 };
01552 
01553 static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
01554 {
01555        zval **value;
01556        zend_uchar key_type;
01557        zend_bool close_fp = 1;
01558        ulong int_key;
01559        struct _phar_t *p_obj = (struct _phar_t*) puser;
01560        uint str_key_len, base_len = p_obj->l, fname_len;
01561        phar_entry_data *data;
01562        php_stream *fp;
01563        size_t contents_len;
01564        char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
01565        phar_zstr key;
01566        char *str_key;
01567        zend_class_entry *ce = p_obj->c;
01568        phar_archive_object *phar_obj = p_obj->p;
01569        char *str = "[stream]";
01570 
01571        iter->funcs->get_current_data(iter, &value TSRMLS_CC);
01572 
01573        if (EG(exception)) {
01574               return ZEND_HASH_APPLY_STOP;
01575        }
01576 
01577        if (!value) {
01578               /* failure in get_current_data */
01579               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned no value", ce->name);
01580               return ZEND_HASH_APPLY_STOP;
01581        }
01582 
01583        switch (Z_TYPE_PP(value)) {
01584 #if PHP_VERSION_ID >= 60000
01585               case IS_UNICODE:
01586                      zval_unicode_to_string(*(value) TSRMLS_CC);
01587                      /* break intentionally omitted */
01588 #endif
01589               case IS_STRING:
01590                      break;
01591               case IS_RESOURCE:
01592                      php_stream_from_zval_no_verify(fp, value);
01593 
01594                      if (!fp) {
01595                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returned an invalid stream handle", ce->name);
01596                             return ZEND_HASH_APPLY_STOP;
01597                      }
01598 
01599                      if (iter->funcs->get_current_key) {
01600                             key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
01601 
01602                             if (EG(exception)) {
01603                                    return ZEND_HASH_APPLY_STOP;
01604                             }
01605 
01606                             if (key_type == HASH_KEY_IS_LONG) {
01607                                    zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
01608                                    return ZEND_HASH_APPLY_STOP;
01609                             }
01610 
01611                             if (key_type > 9) { /* IS_UNICODE == 10 */
01612 #if PHP_VERSION_ID < 60000
01613 /* this can never happen, but fixes a compile warning */
01614                                    spprintf(&str_key, 0, "%s", key);
01615 #else
01616                                    spprintf(&str_key, 0, "%v", key);
01617                                    ezfree(key);
01618 #endif
01619                             } else {
01620                                    PHAR_STR(key, str_key);
01621                             }
01622 
01623                             save = str_key;
01624 
01625                             if (str_key[str_key_len - 1] == '\0') {
01626                                    str_key_len--;
01627                             }
01628 
01629                      } else {
01630                             zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
01631                             return ZEND_HASH_APPLY_STOP;
01632                      }
01633 
01634                      close_fp = 0;
01635                      opened = (char *) estrndup(str, sizeof("[stream]") + 1);
01636                      goto after_open_fp;
01637               case IS_OBJECT:
01638                      if (instanceof_function(Z_OBJCE_PP(value), spl_ce_SplFileInfo TSRMLS_CC)) {
01639                             char *test = NULL;
01640                             zval dummy;
01641                             spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(*value TSRMLS_CC);
01642 
01643                             if (!base_len) {
01644                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returns an SplFileInfo object, so base directory must be specified", ce->name);
01645                                    return ZEND_HASH_APPLY_STOP;
01646                             }
01647 
01648                             switch (intern->type) {
01649                                    case SPL_FS_DIR:
01650 #if PHP_VERSION_ID >= 60000
01651                                           test = spl_filesystem_object_get_path(intern, NULL, NULL TSRMLS_CC).s;
01652 #elif PHP_VERSION_ID >= 50300
01653                                           test = spl_filesystem_object_get_path(intern, NULL TSRMLS_CC);
01654 #else
01655                                           test = intern->path;
01656 #endif
01657                                           fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
01658                                           php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC);
01659 
01660                                           if (Z_BVAL(dummy)) {
01661                                                  /* ignore directories */
01662                                                  efree(fname);
01663                                                  return ZEND_HASH_APPLY_KEEP;
01664                                           }
01665 
01666                                           test = expand_filepath(fname, NULL TSRMLS_CC);
01667                                           efree(fname);
01668 
01669                                           if (test) {
01670                                                  fname = test;
01671                                                  fname_len = strlen(fname);
01672                                           } else {
01673                                                  zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Could not resolve file path");
01674                                                  return ZEND_HASH_APPLY_STOP;
01675                                           }
01676 
01677                                           save = fname;
01678                                           goto phar_spl_fileinfo;
01679                                    case SPL_FS_INFO:
01680                                    case SPL_FS_FILE:
01681 #if PHP_VERSION_ID >= 60000
01682                                           if (intern->file_name_type == IS_UNICODE) {
01683                                                  zval zv;
01684 
01685                                                  INIT_ZVAL(zv);
01686                                                  Z_UNIVAL(zv) = intern->file_name;
01687                                                  Z_UNILEN(zv) = intern->file_name_len;
01688                                                  Z_TYPE(zv) = IS_UNICODE;
01689 
01690                                                  zval_copy_ctor(&zv);
01691                                                  zval_unicode_to_string(&zv TSRMLS_CC);
01692                                                  fname = expand_filepath(Z_STRVAL(zv), NULL TSRMLS_CC);
01693                                                  ezfree(Z_UNIVAL(zv));
01694                                           } else {
01695                                                  fname = expand_filepath(intern->file_name.s, NULL TSRMLS_CC);
01696                                           }
01697 #else
01698                                           fname = expand_filepath(intern->file_name, NULL TSRMLS_CC);
01699 #endif
01700                                           if (!fname) {
01701                                                  zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Could not resolve file path");
01702                                                  return ZEND_HASH_APPLY_STOP;
01703                                           }
01704 
01705                                           fname_len = strlen(fname);
01706                                           save = fname;
01707                                           goto phar_spl_fileinfo;
01708                             }
01709                      }
01710                      /* fall-through */
01711               default:
01712                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid value (must return a string)", ce->name);
01713                      return ZEND_HASH_APPLY_STOP;
01714        }
01715 
01716        fname = Z_STRVAL_PP(value);
01717        fname_len = Z_STRLEN_PP(value);
01718 
01719 phar_spl_fileinfo:
01720        if (base_len) {
01721               temp = expand_filepath(base, NULL TSRMLS_CC);
01722               if (!temp) {
01723                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Could not resolve file path");
01724                      if (save) {
01725                             efree(save);
01726                      }
01727                      return ZEND_HASH_APPLY_STOP;
01728               }
01729               
01730               base = temp;
01731               base_len = strlen(base);
01732 
01733               if (strstr(fname, base)) {
01734                      str_key_len = fname_len - base_len;
01735 
01736                      if (str_key_len <= 0) {
01737                             if (save) {
01738                                    efree(save);
01739                                    efree(temp);
01740                             }
01741                             return ZEND_HASH_APPLY_KEEP;
01742                      }
01743 
01744                      str_key = fname + base_len;
01745 
01746                      if (*str_key == '/' || *str_key == '\\') {
01747                             str_key++;
01748                             str_key_len--;
01749                      }
01750 
01751               } else {
01752                      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);
01753 
01754                      if (save) {
01755                             efree(save);
01756                             efree(temp);
01757                      }
01758 
01759                      return ZEND_HASH_APPLY_STOP;
01760               }
01761        } else {
01762               if (iter->funcs->get_current_key) {
01763                      key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
01764 
01765                      if (EG(exception)) {
01766                             return ZEND_HASH_APPLY_STOP;
01767                      }
01768 
01769                      if (key_type == HASH_KEY_IS_LONG) {
01770                             zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
01771                             return ZEND_HASH_APPLY_STOP;
01772                      }
01773 
01774                      if (key_type > 9) { /* IS_UNICODE == 10 */
01775 #if PHP_VERSION_ID < 60000
01776 /* this can never happen, but fixes a compile warning */
01777                             spprintf(&str_key, 0, "%s", key);
01778 #else
01779                             spprintf(&str_key, 0, "%v", key);
01780                             ezfree(key);
01781 #endif
01782                      } else {
01783                             PHAR_STR(key, str_key);
01784                      }
01785 
01786                      save = str_key;
01787 
01788                      if (str_key[str_key_len - 1] == '\0') str_key_len--;
01789               } else {
01790                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
01791                      return ZEND_HASH_APPLY_STOP;
01792               }
01793        }
01794 #if PHP_API_VERSION < 20100412
01795        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
01796               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that safe mode prevents opening", ce->name, fname);
01797 
01798               if (save) {
01799                      efree(save);
01800               }
01801 
01802               if (temp) {
01803                      efree(temp);
01804               }
01805 
01806               return ZEND_HASH_APPLY_STOP;
01807        }
01808 #endif
01809 
01810        if (php_check_open_basedir(fname TSRMLS_CC)) {
01811               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that open_basedir prevents opening", ce->name, fname);
01812 
01813               if (save) {
01814                      efree(save);
01815               }
01816 
01817               if (temp) {
01818                      efree(temp);
01819               }
01820 
01821               return ZEND_HASH_APPLY_STOP;
01822        }
01823 
01824        /* try to open source file, then create internal phar file and copy contents */
01825        fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened);
01826 
01827        if (!fp) {
01828               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a file that could not be opened \"%s\"", ce->name, fname);
01829 
01830               if (save) {
01831                      efree(save);
01832               }
01833 
01834               if (temp) {
01835                      efree(temp);
01836               }
01837 
01838               return ZEND_HASH_APPLY_STOP;
01839        }
01840 after_open_fp:
01841        if (str_key_len >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
01842               /* silently skip any files that would be added to the magic .phar directory */
01843               if (save) {
01844                      efree(save);
01845               }
01846 
01847               if (temp) {
01848                      efree(temp);
01849               }
01850 
01851               if (opened) {
01852                      efree(opened);
01853               }
01854 
01855               if (close_fp) {
01856                      php_stream_close(fp);
01857               }
01858 
01859               return ZEND_HASH_APPLY_KEEP;
01860        }
01861 
01862        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))) {
01863               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error);
01864               efree(error);
01865 
01866               if (save) {
01867                      efree(save);
01868               }
01869 
01870               if (opened) {
01871                      efree(opened);
01872               }
01873 
01874               if (temp) {
01875                      efree(temp);
01876               }
01877 
01878               if (close_fp) {
01879                      php_stream_close(fp);
01880               }
01881 
01882               return ZEND_HASH_APPLY_STOP;
01883 
01884        } else {
01885               if (error) {
01886                      efree(error);
01887               }
01888               /* convert to PHAR_UFP */
01889               if (data->internal_file->fp_type == PHAR_MOD) {
01890                      php_stream_close(data->internal_file->fp);
01891               }
01892 
01893               data->internal_file->fp = NULL;
01894               data->internal_file->fp_type = PHAR_UFP;
01895               data->internal_file->offset_abs = data->internal_file->offset = php_stream_tell(p_obj->fp);
01896               data->fp = NULL;
01897               phar_stream_copy_to_stream(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len);
01898               data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize =
01899                      php_stream_tell(p_obj->fp) - data->internal_file->offset;
01900        }
01901 
01902        if (close_fp) {
01903               php_stream_close(fp);
01904        }
01905 
01906        add_assoc_string(p_obj->ret, str_key, opened, 0);
01907 
01908        if (save) {
01909               efree(save);
01910        }
01911 
01912        if (temp) {
01913               efree(temp);
01914        }
01915 
01916        data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
01917        phar_entry_delref(data TSRMLS_CC);
01918 
01919        return ZEND_HASH_APPLY_KEEP;
01920 }
01921 /* }}} */
01922 
01923 /* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex])
01924  * Construct a phar archive from an existing directory, recursively.
01925  * Optional second parameter is a regular expression for filtering directory contents.
01926  * 
01927  * Return value is an array mapping phar index to actual files added.
01928  */
01929 PHP_METHOD(Phar, buildFromDirectory)
01930 {
01931        char *dir, *error, *regex = NULL;
01932        int dir_len, regex_len = 0;
01933        zend_bool apply_reg = 0;
01934        zval arg, arg2, *iter, *iteriter, *regexiter = NULL;
01935        struct _phar_t pass;
01936 
01937        PHAR_ARCHIVE_OBJECT();
01938 
01939        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
01940               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
01941                      "Cannot write to archive - write operations restricted by INI setting");
01942               return;
01943        }
01944 
01945        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &dir, &dir_len, &regex, &regex_len) == FAILURE) {
01946               RETURN_FALSE;
01947        }
01948 
01949        MAKE_STD_ZVAL(iter);
01950 
01951        if (SUCCESS != object_init_ex(iter, spl_ce_RecursiveDirectoryIterator)) {
01952               zval_ptr_dtor(&iter);
01953               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
01954               RETURN_FALSE;
01955        }
01956 
01957        INIT_PZVAL(&arg);
01958        ZVAL_STRINGL(&arg, dir, dir_len, 0);
01959        INIT_PZVAL(&arg2);
01960 #if PHP_VERSION_ID < 50300
01961        ZVAL_LONG(&arg2, 0);
01962 #else
01963        ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS);
01964 #endif
01965 
01966        zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator, 
01967                      &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2);
01968 
01969        if (EG(exception)) {
01970               zval_ptr_dtor(&iter);
01971               RETURN_FALSE;
01972        }
01973 
01974        MAKE_STD_ZVAL(iteriter);
01975 
01976        if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) {
01977               zval_ptr_dtor(&iter);
01978               zval_ptr_dtor(&iteriter);
01979               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
01980               RETURN_FALSE;
01981        }
01982 
01983        zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator, 
01984                      &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter);
01985 
01986        if (EG(exception)) {
01987               zval_ptr_dtor(&iter);
01988               zval_ptr_dtor(&iteriter);
01989               RETURN_FALSE;
01990        }
01991 
01992        zval_ptr_dtor(&iter);
01993 
01994        if (regex_len > 0) {
01995               apply_reg = 1;
01996               MAKE_STD_ZVAL(regexiter);
01997 
01998               if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) {
01999                      zval_ptr_dtor(&iteriter);
02000                      zval_dtor(regexiter);
02001                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname);
02002                      RETURN_FALSE;
02003               }
02004 
02005               INIT_PZVAL(&arg2);
02006               ZVAL_STRINGL(&arg2, regex, regex_len, 0);
02007 
02008               zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator, 
02009                      &spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2);
02010        }
02011 
02012        array_init(return_value);
02013 
02014        pass.c = apply_reg ? Z_OBJCE_P(regexiter) : Z_OBJCE_P(iteriter);
02015        pass.p = phar_obj;
02016        pass.b = dir;
02017        pass.l = dir_len;
02018        pass.count = 0;
02019        pass.ret = return_value;
02020        pass.fp = php_stream_fopen_tmpfile();
02021 
02022        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
02023               zval_ptr_dtor(&iteriter);
02024               if (apply_reg) {
02025                      zval_ptr_dtor(&regexiter);
02026               }
02027               php_stream_close(pass.fp);
02028               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
02029               return;
02030        }
02031 
02032        if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
02033               zval_ptr_dtor(&iteriter);
02034 
02035               if (apply_reg) {
02036                      zval_ptr_dtor(&regexiter);
02037               }
02038 
02039               phar_obj->arc.archive->ufp = pass.fp;
02040               phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
02041 
02042               if (error) {
02043                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
02044                      efree(error);
02045               }
02046 
02047        } else {
02048               zval_ptr_dtor(&iteriter);
02049               if (apply_reg) {
02050                      zval_ptr_dtor(&regexiter);
02051               }
02052               php_stream_close(pass.fp);
02053        }
02054 }
02055 /* }}} */
02056 
02057 /* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory])
02058  * Construct a phar archive from an iterator.  The iterator must return a series of strings
02059  * that are full paths to files that should be added to the phar.  The iterator key should
02060  * be the path that the file will have within the phar archive.
02061  *
02062  * If base directory is specified, then the key will be ignored, and instead the portion of
02063  * the current value minus the base directory will be used
02064  *
02065  * Returned is an array mapping phar index to actual file added
02066  */
02067 PHP_METHOD(Phar, buildFromIterator)
02068 {
02069        zval *obj;
02070        char *error;
02071        uint base_len = 0;
02072        char *base = NULL;
02073        struct _phar_t pass;
02074 
02075        PHAR_ARCHIVE_OBJECT();
02076 
02077        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
02078               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02079                      "Cannot write out phar archive, phar is read-only");
02080               return;
02081        }
02082 
02083        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &obj, zend_ce_traversable, &base, &base_len) == FAILURE) {
02084               RETURN_FALSE;
02085        }
02086 
02087        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
02088               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
02089               return;
02090        }
02091 
02092        array_init(return_value);
02093 
02094        pass.c = Z_OBJCE_P(obj);
02095        pass.p = phar_obj;
02096        pass.b = base;
02097        pass.l = base_len;
02098        pass.ret = return_value;
02099        pass.count = 0;
02100        pass.fp = php_stream_fopen_tmpfile();
02101 
02102        if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
02103               phar_obj->arc.archive->ufp = pass.fp;
02104               phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
02105               if (error) {
02106                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
02107                      efree(error);
02108               }
02109        } else {
02110               php_stream_close(pass.fp);
02111        }
02112 }
02113 /* }}} */
02114 
02115 /* {{{ proto int Phar::count()
02116  * Returns the number of entries in the Phar archive
02117  */
02118 PHP_METHOD(Phar, count)
02119 {
02120        PHAR_ARCHIVE_OBJECT();
02121        
02122        if (zend_parse_parameters_none() == FAILURE) {
02123               return;
02124        }
02125 
02126        RETURN_LONG(zend_hash_num_elements(&phar_obj->arc.archive->manifest));
02127 }
02128 /* }}} */
02129 
02130 /* {{{ proto bool Phar::isFileFormat(int format)
02131  * Returns true if the phar archive is based on the tar/zip/phar file format depending
02132  * on whether Phar::TAR, Phar::ZIP or Phar::PHAR was passed in
02133  */
02134 PHP_METHOD(Phar, isFileFormat)
02135 {
02136        long type;
02137        PHAR_ARCHIVE_OBJECT();
02138 
02139        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
02140               RETURN_FALSE;
02141        }
02142 
02143        switch (type) {
02144               case PHAR_FORMAT_TAR:
02145                      RETURN_BOOL(phar_obj->arc.archive->is_tar);
02146               case PHAR_FORMAT_ZIP:
02147                      RETURN_BOOL(phar_obj->arc.archive->is_zip);
02148               case PHAR_FORMAT_PHAR:
02149                      RETURN_BOOL(!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip);
02150               default:
02151                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown file format specified");
02152        }
02153 }
02154 /* }}} */
02155 
02156 static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */
02157 {
02158        char *error;
02159        off_t offset;
02160        phar_entry_info *link;
02161 
02162        if (FAILURE == phar_open_entry_fp(entry, &error, 1 TSRMLS_CC)) {
02163               if (error) {
02164                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02165                             "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error);
02166                      efree(error);
02167               } else {
02168                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02169                             "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename);
02170               }
02171               return FAILURE;
02172        }
02173 
02174        /* copy old contents in entirety */
02175        phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
02176        offset = php_stream_tell(fp);
02177        link = phar_get_link_source(entry TSRMLS_CC);
02178 
02179        if (!link) {
02180               link = entry;
02181        }
02182 
02183        if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
02184               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02185                      "Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
02186               return FAILURE;
02187        }
02188 
02189        if (entry->fp_type == PHAR_MOD) {
02190               /* save for potential restore on error */
02191               entry->cfp = entry->fp;
02192               entry->fp = NULL;
02193        }
02194 
02195        /* set new location of file contents */
02196        entry->fp_type = PHAR_FP;
02197        entry->offset = offset;
02198        return SUCCESS;
02199 }
02200 /* }}} */
02201 
02202 static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC) /* {{{ */
02203 {
02204        char *oldname = NULL, *oldpath = NULL;
02205        char *basename = NULL, *basepath = NULL;
02206        char *newname = NULL, *newpath = NULL;
02207        zval *ret, arg1;
02208        zend_class_entry *ce;
02209        char *error;
02210        const char *pcr_error;
02211        int ext_len = ext ? strlen(ext) : 0;
02212        int oldname_len;
02213        phar_archive_data **pphar = NULL;
02214        php_stream_statbuf ssb;
02215 
02216        if (!ext) {
02217               if (phar->is_zip) {
02218 
02219                      if (phar->is_data) {
02220                             ext = "zip";
02221                      } else {
02222                             ext = "phar.zip";
02223                      }
02224 
02225               } else if (phar->is_tar) {
02226 
02227                      switch (phar->flags) {
02228                             case PHAR_FILE_COMPRESSED_GZ:
02229                                    if (phar->is_data) {
02230                                           ext = "tar.gz";
02231                                    } else {
02232                                           ext = "phar.tar.gz";
02233                                    }
02234                                    break;
02235                             case PHAR_FILE_COMPRESSED_BZ2:
02236                                    if (phar->is_data) {
02237                                           ext = "tar.bz2";
02238                                    } else {
02239                                           ext = "phar.tar.bz2";
02240                                    }
02241                                    break;
02242                             default:
02243                                    if (phar->is_data) {
02244                                           ext = "tar";
02245                                    } else {
02246                                           ext = "phar.tar";
02247                                    }
02248                      }
02249               } else {
02250 
02251                      switch (phar->flags) {
02252                             case PHAR_FILE_COMPRESSED_GZ:
02253                                    ext = "phar.gz";
02254                                    break;
02255                             case PHAR_FILE_COMPRESSED_BZ2:
02256                                    ext = "phar.bz2";
02257                                    break;
02258                             default:
02259                                    ext = "phar";
02260                      }
02261               }
02262        } else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) {
02263 
02264               if (phar->is_data) {
02265                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
02266               } else {
02267                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
02268               }
02269               return NULL;
02270        }
02271 
02272        if (ext[0] == '.') {
02273               ++ext;
02274        }
02275 
02276        oldpath = estrndup(phar->fname, phar->fname_len);
02277        oldname = zend_memrchr(phar->fname, '/', phar->fname_len);
02278        ++oldname;
02279        oldname_len = strlen(oldname);
02280 
02281        basename = estrndup(oldname, oldname_len);
02282        spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext);
02283        efree(basename);
02284 
02285        
02286 
02287        basepath = estrndup(oldpath, (strlen(oldpath) - oldname_len));
02288        phar->fname_len = spprintf(&newpath, 0, "%s%s", basepath, newname);
02289        phar->fname = newpath;
02290        phar->ext = newpath + phar->fname_len - strlen(ext) - 1;
02291        efree(basepath);
02292        efree(newname);
02293 
02294        if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, newpath, phar->fname_len, (void **) &pphar)) {
02295               efree(oldpath);
02296               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);
02297               return NULL;
02298        }
02299 
02300        if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void **) &pphar)) {
02301               if ((*pphar)->fname_len == phar->fname_len && !memcmp((*pphar)->fname, phar->fname, phar->fname_len)) {
02302                      if (!zend_hash_num_elements(&phar->manifest)) {
02303                             (*pphar)->is_tar = phar->is_tar;
02304                             (*pphar)->is_zip = phar->is_zip;
02305                             (*pphar)->is_data = phar->is_data;
02306                             (*pphar)->flags = phar->flags;
02307                             (*pphar)->fp = phar->fp;
02308                             phar->fp = NULL;
02309                             phar_destroy_phar_data(phar TSRMLS_CC);
02310                             phar = *pphar;
02311                             phar->refcount++;
02312                             newpath = oldpath;
02313                             goto its_ok;
02314                      }
02315               }
02316 
02317               efree(oldpath);
02318               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);
02319               return NULL;
02320        }
02321 its_ok:
02322        if (SUCCESS == php_stream_stat_path(newpath, &ssb)) {
02323               efree(oldpath);
02324               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" exists and must be unlinked prior to conversion", newpath);
02325               return NULL;
02326        }
02327        if (!phar->is_data) {
02328               if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) {
02329                      efree(oldpath);
02330                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext);
02331                      return NULL;
02332               }
02333 
02334               if (phar->alias) {
02335                      if (phar->is_temporary_alias) {
02336                             phar->alias = NULL;
02337                             phar->alias_len = 0;
02338                      } else {
02339                             phar->alias = estrndup(newpath, strlen(newpath));
02340                             phar->alias_len = strlen(newpath);
02341                             phar->is_temporary_alias = 1;
02342                             zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL);
02343                      }
02344               }
02345 
02346        } else {
02347 
02348               if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) {
02349                      efree(oldpath);
02350                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
02351                      return NULL;
02352               }
02353 
02354               phar->alias = NULL;
02355               phar->alias_len = 0;
02356        }
02357 
02358        if ((!pphar || phar == *pphar) && SUCCESS != zend_hash_update(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL)) {
02359               efree(oldpath);
02360               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname);
02361               return NULL;
02362        }
02363 
02364        phar_flush(phar, 0, 0, 1, &error TSRMLS_CC);
02365 
02366        if (error) {
02367               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s", error);
02368               efree(error);
02369               efree(oldpath);
02370               return NULL;
02371        }
02372 
02373        efree(oldpath);
02374 
02375        if (phar->is_data) {
02376               ce = phar_ce_data;
02377        } else {
02378               ce = phar_ce_archive;
02379        }
02380 
02381        MAKE_STD_ZVAL(ret);
02382 
02383        if (SUCCESS != object_init_ex(ret, ce)) {
02384               zval_dtor(ret);
02385               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname);
02386               return NULL;
02387        }
02388 
02389        INIT_PZVAL(&arg1);
02390        ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len, 0);
02391 
02392        zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1);
02393        return ret;
02394 }
02395 /* }}} */
02396 
02397 static zval *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, php_uint32 flags TSRMLS_DC) /* {{{ */
02398 {
02399        phar_archive_data *phar;
02400        phar_entry_info *entry, newentry;
02401        zval *ret;
02402 
02403        /* invalidate phar cache */
02404        PHAR_G(last_phar) = NULL;
02405        PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
02406 
02407        phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
02408        /* set whole-archive compression and type from parameter */
02409        phar->flags = flags;
02410        phar->is_data = source->is_data;
02411 
02412        switch (convert) {
02413               case PHAR_FORMAT_TAR:
02414                      phar->is_tar = 1;
02415                      break;
02416               case PHAR_FORMAT_ZIP:
02417                      phar->is_zip = 1;
02418                      break;
02419               default:
02420                      phar->is_data = 0;
02421                      break;
02422        }
02423 
02424        zend_hash_init(&(phar->manifest), sizeof(phar_entry_info),
02425               zend_get_hash_value, destroy_phar_manifest_entry, 0);
02426        zend_hash_init(&phar->mounted_dirs, sizeof(char *),
02427               zend_get_hash_value, NULL, 0);
02428        zend_hash_init(&phar->virtual_dirs, sizeof(char *),
02429               zend_get_hash_value, NULL, 0);
02430 
02431        phar->fp = php_stream_fopen_tmpfile();
02432        phar->fname = source->fname;
02433        phar->fname_len = source->fname_len;
02434        phar->is_temporary_alias = source->is_temporary_alias;
02435        phar->alias = source->alias;
02436 
02437        if (source->metadata) {
02438               zval *t;
02439 
02440               t = source->metadata;
02441               ALLOC_ZVAL(phar->metadata);
02442               *phar->metadata = *t;
02443               zval_copy_ctor(phar->metadata);
02444 #if PHP_VERSION_ID < 50300
02445               phar->metadata->refcount = 1;
02446 #else
02447               Z_SET_REFCOUNT_P(phar->metadata, 1);
02448 #endif
02449 
02450               phar->metadata_len = 0;
02451        }
02452 
02453        /* first copy each file's uncompressed contents to a temporary file and set per-file flags */
02454        for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) {
02455 
02456               if (FAILURE == zend_hash_get_current_data(&source->manifest, (void **) &entry)) {
02457                      zend_hash_destroy(&(phar->manifest));
02458                      php_stream_close(phar->fp);
02459                      efree(phar);
02460                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02461                             "Cannot convert phar archive \"%s\"", source->fname);
02462                      return NULL;
02463               }
02464 
02465               newentry = *entry;
02466 
02467               if (newentry.link) {
02468                      newentry.link = estrdup(newentry.link);
02469                      goto no_copy;
02470               }
02471 
02472               if (newentry.tmp) {
02473                      newentry.tmp = estrdup(newentry.tmp);
02474                      goto no_copy;
02475               }
02476 
02477               newentry.metadata_str.c = 0;
02478 
02479               if (FAILURE == phar_copy_file_contents(&newentry, phar->fp TSRMLS_CC)) {
02480                      zend_hash_destroy(&(phar->manifest));
02481                      php_stream_close(phar->fp);
02482                      efree(phar);
02483                      /* exception already thrown */
02484                      return NULL;
02485               }
02486 no_copy:
02487               newentry.filename = estrndup(newentry.filename, newentry.filename_len);
02488 
02489               if (newentry.metadata) {
02490                      zval *t;
02491 
02492                      t = newentry.metadata;
02493                      ALLOC_ZVAL(newentry.metadata);
02494                      *newentry.metadata = *t;
02495                      zval_copy_ctor(newentry.metadata);
02496 #if PHP_VERSION_ID < 50300
02497                      newentry.metadata->refcount = 1;
02498 #else
02499                      Z_SET_REFCOUNT_P(newentry.metadata, 1);
02500 #endif
02501 
02502                      newentry.metadata_str.c = NULL;
02503                      newentry.metadata_str.len = 0;
02504               }
02505 
02506               newentry.is_zip = phar->is_zip;
02507               newentry.is_tar = phar->is_tar;
02508 
02509               if (newentry.is_tar) {
02510                      newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE);
02511               }
02512 
02513               newentry.is_modified = 1;
02514               newentry.phar = phar;
02515               newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
02516               phar_set_inode(&newentry TSRMLS_CC);
02517               zend_hash_add(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
02518               phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len TSRMLS_CC);
02519        }
02520 
02521        if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) {
02522               return ret;
02523        } else {
02524               zend_hash_destroy(&(phar->manifest));
02525               zend_hash_destroy(&(phar->mounted_dirs));
02526               zend_hash_destroy(&(phar->virtual_dirs));
02527               php_stream_close(phar->fp);
02528               efree(phar->fname);
02529               efree(phar);
02530               return NULL;
02531        }
02532 }
02533 /* }}} */
02534 
02535 /* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]])
02536  * Convert a phar.tar or phar.zip archive to the phar file format. The
02537  * optional parameter allows the user to determine the new
02538  * filename extension (default is phar).
02539  */
02540 PHP_METHOD(Phar, convertToExecutable)
02541 {
02542        char *ext = NULL;
02543        int is_data, ext_len = 0;
02544        php_uint32 flags;
02545        zval *ret;
02546        /* a number that is not 0, 1 or 2 (Which is also Greg's birthday, so there) */
02547        long format = 9021976, method = 9021976;
02548        PHAR_ARCHIVE_OBJECT();
02549 
02550        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
02551               return;
02552        }
02553 
02554        if (PHAR_G(readonly)) {
02555               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02556                      "Cannot write out executable phar archive, phar is read-only");
02557               return;
02558        }
02559 
02560        switch (format) {
02561               case 9021976:
02562               case PHAR_FORMAT_SAME: /* null is converted to 0 */
02563                      /* by default, use the existing format */
02564                      if (phar_obj->arc.archive->is_tar) {
02565                             format = PHAR_FORMAT_TAR;
02566                      } else if (phar_obj->arc.archive->is_zip) {
02567                             format = PHAR_FORMAT_ZIP;
02568                      } else {
02569                             format = PHAR_FORMAT_PHAR;
02570                      }
02571                      break;
02572               case PHAR_FORMAT_PHAR:
02573               case PHAR_FORMAT_TAR:
02574               case PHAR_FORMAT_ZIP:
02575                      break;
02576               default:
02577                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02578                             "Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP");
02579                      return;
02580        }
02581 
02582        switch (method) {
02583               case 9021976:
02584                      flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
02585                      break;
02586               case 0:
02587                      flags = PHAR_FILE_COMPRESSED_NONE;
02588                      break;
02589               case PHAR_ENT_COMPRESSED_GZ:
02590                      if (format == PHAR_FORMAT_ZIP) {
02591                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02592                                    "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
02593                             return;
02594                      }
02595 
02596                      if (!PHAR_G(has_zlib)) {
02597                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02598                                    "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
02599                             return;
02600                      }
02601 
02602                      flags = PHAR_FILE_COMPRESSED_GZ;
02603                      break;
02604               case PHAR_ENT_COMPRESSED_BZ2:
02605                      if (format == PHAR_FORMAT_ZIP) {
02606                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02607                                    "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
02608                             return;
02609                      }
02610 
02611                      if (!PHAR_G(has_bz2)) {
02612                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02613                                    "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
02614                             return;
02615                      }
02616 
02617                      flags = PHAR_FILE_COMPRESSED_BZ2;
02618                      break;
02619               default:
02620                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02621                             "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
02622                      return;
02623        }
02624 
02625        is_data = phar_obj->arc.archive->is_data;
02626        phar_obj->arc.archive->is_data = 0;
02627        ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
02628        phar_obj->arc.archive->is_data = is_data;
02629 
02630        if (ret) {
02631               RETURN_ZVAL(ret, 1, 1);
02632        } else {
02633               RETURN_NULL();
02634        }
02635 }
02636 /* }}} */
02637 
02638 /* {{{ proto object Phar::convertToData([int format[, int compression [, string file_ext]]])
02639  * Convert an archive to a non-executable .tar or .zip.
02640  * The optional parameter allows the user to determine the new
02641  * filename extension (default is .zip or .tar).
02642  */
02643 PHP_METHOD(Phar, convertToData)
02644 {
02645        char *ext = NULL;
02646        int is_data, ext_len = 0;
02647        php_uint32 flags;
02648        zval *ret;
02649        /* a number that is not 0, 1 or 2 (Which is also Greg's birthday so there) */
02650        long format = 9021976, method = 9021976;
02651        PHAR_ARCHIVE_OBJECT();
02652 
02653        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
02654               return;
02655        }
02656 
02657        switch (format) {
02658               case 9021976:
02659               case PHAR_FORMAT_SAME: /* null is converted to 0 */
02660                      /* by default, use the existing format */
02661                      if (phar_obj->arc.archive->is_tar) {
02662                             format = PHAR_FORMAT_TAR;
02663                      } else if (phar_obj->arc.archive->is_zip) {
02664                             format = PHAR_FORMAT_ZIP;
02665                      } else {
02666                             zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02667                                    "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
02668                             return;
02669                      }
02670                      break;
02671               case PHAR_FORMAT_PHAR:
02672                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02673                             "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
02674                      return;
02675               case PHAR_FORMAT_TAR:
02676               case PHAR_FORMAT_ZIP:
02677                      break;
02678               default:
02679                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02680                             "Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP");
02681                      return;
02682        }
02683 
02684        switch (method) {
02685               case 9021976:
02686                      flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
02687                      break;
02688               case 0:
02689                      flags = PHAR_FILE_COMPRESSED_NONE;
02690                      break;
02691               case PHAR_ENT_COMPRESSED_GZ:
02692                      if (format == PHAR_FORMAT_ZIP) {
02693                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02694                                    "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
02695                             return;
02696                      }
02697 
02698                      if (!PHAR_G(has_zlib)) {
02699                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02700                                    "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
02701                             return;
02702                      }
02703 
02704                      flags = PHAR_FILE_COMPRESSED_GZ;
02705                      break;
02706               case PHAR_ENT_COMPRESSED_BZ2:
02707                      if (format == PHAR_FORMAT_ZIP) {
02708                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02709                                    "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
02710                             return;
02711                      }
02712 
02713                      if (!PHAR_G(has_bz2)) {
02714                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02715                                    "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
02716                             return;
02717                      }
02718 
02719                      flags = PHAR_FILE_COMPRESSED_BZ2;
02720                      break;
02721               default:
02722                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
02723                             "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
02724                      return;
02725        }
02726 
02727        is_data = phar_obj->arc.archive->is_data;
02728        phar_obj->arc.archive->is_data = 1;
02729        ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
02730        phar_obj->arc.archive->is_data = is_data;
02731 
02732        if (ret) {
02733               RETURN_ZVAL(ret, 1, 1);
02734        } else {
02735               RETURN_NULL();
02736        }
02737 }
02738 /* }}} */
02739 
02740 /* {{{ proto int|false Phar::isCompressed()
02741  * Returns Phar::GZ or PHAR::BZ2 if the entire archive is compressed
02742  * (.tar.gz/tar.bz2 and so on), or FALSE otherwise.
02743  */
02744 PHP_METHOD(Phar, isCompressed)
02745 {
02746        PHAR_ARCHIVE_OBJECT();
02747        
02748        if (zend_parse_parameters_none() == FAILURE) {
02749               return;
02750        }
02751 
02752        if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_GZ) {
02753               RETURN_LONG(PHAR_ENT_COMPRESSED_GZ);
02754        }
02755 
02756        if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_BZ2) {
02757               RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2);
02758        }
02759 
02760        RETURN_FALSE;
02761 }
02762 /* }}} */
02763 
02764 /* {{{ proto bool Phar::isWritable()
02765  * Returns true if phar.readonly=0 or phar is a PharData AND the actual file is writable.
02766  */
02767 PHP_METHOD(Phar, isWritable)
02768 {
02769        php_stream_statbuf ssb;
02770        PHAR_ARCHIVE_OBJECT();
02771        
02772        if (zend_parse_parameters_none() == FAILURE) {
02773               return;
02774        }
02775 
02776        if (!phar_obj->arc.archive->is_writeable) {
02777               RETURN_FALSE;
02778        }
02779 
02780        if (SUCCESS != php_stream_stat_path(phar_obj->arc.archive->fname, &ssb)) {
02781               if (phar_obj->arc.archive->is_brandnew) {
02782                      /* assume it works if the file doesn't exist yet */
02783                      RETURN_TRUE;
02784               }
02785               RETURN_FALSE;
02786        }
02787 
02788        RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0);
02789 }
02790 /* }}} */
02791 
02792 /* {{{ proto bool Phar::delete(string entry)
02793  * Deletes a named file within the archive.
02794  */
02795 PHP_METHOD(Phar, delete)
02796 {
02797        char *fname;
02798        int fname_len;
02799        char *error;
02800        phar_entry_info *entry;
02801        PHAR_ARCHIVE_OBJECT();
02802 
02803        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
02804               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02805                      "Cannot write out phar archive, phar is read-only");
02806               return;
02807        }
02808 
02809        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
02810               RETURN_FALSE;
02811        }
02812 
02813        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
02814               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
02815               return;
02816        }
02817        if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
02818               if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
02819                      if (entry->is_deleted) {
02820                             /* entry is deleted, but has not been flushed to disk yet */
02821                             RETURN_TRUE;
02822                      } else {
02823                             entry->is_deleted = 1;
02824                             entry->is_modified = 1;
02825                             phar_obj->arc.archive->is_modified = 1;
02826                      }
02827               }
02828        } else {
02829               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be deleted", fname);
02830               RETURN_FALSE;
02831        }
02832 
02833        phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
02834        if (error) {
02835               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
02836               efree(error);
02837        }
02838 
02839        RETURN_TRUE;
02840 }
02841 /* }}} */
02842 
02843 /* {{{ proto int Phar::getAlias()
02844  * Returns the alias for the Phar or NULL.
02845  */
02846 PHP_METHOD(Phar, getAlias)
02847 {
02848        PHAR_ARCHIVE_OBJECT();
02849        
02850        if (zend_parse_parameters_none() == FAILURE) {
02851               return;
02852        }
02853 
02854        if (phar_obj->arc.archive->alias && phar_obj->arc.archive->alias != phar_obj->arc.archive->fname) {
02855               RETURN_STRINGL(phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, 1);
02856        }
02857 }
02858 /* }}} */
02859 
02860 /* {{{ proto int Phar::getPath()
02861  * Returns the real path to the phar archive on disk
02862  */
02863 PHP_METHOD(Phar, getPath)
02864 {
02865        PHAR_ARCHIVE_OBJECT();
02866        
02867        if (zend_parse_parameters_none() == FAILURE) {
02868               return;
02869        }
02870 
02871        RETURN_STRINGL(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, 1);
02872 }
02873 /* }}} */
02874 
02875 /* {{{ proto bool Phar::setAlias(string alias)
02876  * Sets the alias for a Phar archive. The default value is the full path
02877  * to the archive.
02878  */
02879 PHP_METHOD(Phar, setAlias)
02880 {
02881        char *alias, *error, *oldalias;
02882        phar_archive_data **fd_ptr;
02883        int alias_len, oldalias_len, old_temp, readd = 0;
02884 
02885        PHAR_ARCHIVE_OBJECT();
02886 
02887        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
02888               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02889                      "Cannot write out phar archive, phar is read-only");
02890               RETURN_FALSE;
02891        }
02892 
02893        /* invalidate phar cache */
02894        PHAR_G(last_phar) = NULL;
02895        PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
02896 
02897        if (phar_obj->arc.archive->is_data) {
02898               if (phar_obj->arc.archive->is_tar) {
02899                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02900                             "A Phar alias cannot be set in a plain tar archive");
02901               } else {
02902                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02903                             "A Phar alias cannot be set in a plain zip archive");
02904               }
02905               RETURN_FALSE;
02906        }
02907 
02908        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &alias, &alias_len) == SUCCESS) {
02909               if (alias_len == phar_obj->arc.archive->alias_len && memcmp(phar_obj->arc.archive->alias, alias, alias_len) == 0) {
02910                      RETURN_TRUE;
02911               }
02912               if (alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
02913                      spprintf(&error, 0, "alias \"%s\" is already used for archive \"%s\" and cannot be used for other archives", alias, (*fd_ptr)->fname);
02914                      if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
02915                             efree(error);
02916                             goto valid_alias;
02917                      }
02918                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
02919                      efree(error);
02920                      RETURN_FALSE;
02921               }
02922               if (!phar_validate_alias(alias, alias_len)) {
02923                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
02924                             "Invalid alias \"%s\" specified for phar \"%s\"", alias, phar_obj->arc.archive->fname);
02925                      RETURN_FALSE;
02926               }
02927 valid_alias:
02928               if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
02929                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
02930                      return;
02931               }
02932               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)) {
02933                      zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len);
02934                      readd = 1;
02935               }
02936 
02937               oldalias = phar_obj->arc.archive->alias;
02938               oldalias_len = phar_obj->arc.archive->alias_len;
02939               old_temp = phar_obj->arc.archive->is_temporary_alias;
02940 
02941               if (alias_len) {
02942                      phar_obj->arc.archive->alias = estrndup(alias, alias_len);
02943               } else {
02944                      phar_obj->arc.archive->alias = NULL;
02945               }
02946 
02947               phar_obj->arc.archive->alias_len = alias_len;
02948               phar_obj->arc.archive->is_temporary_alias = 0;
02949               phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
02950 
02951               if (error) {
02952                      phar_obj->arc.archive->alias = oldalias;
02953                      phar_obj->arc.archive->alias_len = oldalias_len;
02954                      phar_obj->arc.archive->is_temporary_alias = old_temp;
02955                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
02956                      if (readd) {
02957                             zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), oldalias, oldalias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
02958                      }
02959                      efree(error);
02960                      RETURN_FALSE;
02961               }
02962 
02963               zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
02964 
02965               if (oldalias) {
02966                      efree(oldalias);
02967               }
02968 
02969               RETURN_TRUE;
02970        }
02971 
02972        RETURN_FALSE;
02973 }
02974 /* }}} */
02975 
02976 /* {{{ proto string Phar::getVersion()
02977  * Return version info of Phar archive
02978  */
02979 PHP_METHOD(Phar, getVersion)
02980 {
02981        PHAR_ARCHIVE_OBJECT();
02982        
02983        if (zend_parse_parameters_none() == FAILURE) {
02984               return;
02985        }
02986 
02987        RETURN_STRING(phar_obj->arc.archive->version, 1);
02988 }
02989 /* }}} */
02990 
02991 /* {{{ proto void Phar::startBuffering()
02992  * Do not flush a writeable phar (save its contents) until explicitly requested
02993  */
02994 PHP_METHOD(Phar, startBuffering)
02995 {
02996        PHAR_ARCHIVE_OBJECT();
02997        
02998        if (zend_parse_parameters_none() == FAILURE) {
02999               return;
03000        }
03001 
03002        phar_obj->arc.archive->donotflush = 1;
03003 }
03004 /* }}} */
03005 
03006 /* {{{ proto bool Phar::isBuffering()
03007  * Returns whether write operations are flushing to disk immediately.
03008  */
03009 PHP_METHOD(Phar, isBuffering)
03010 {
03011        PHAR_ARCHIVE_OBJECT();
03012        
03013        if (zend_parse_parameters_none() == FAILURE) {
03014               return;
03015        }
03016 
03017        RETURN_BOOL(phar_obj->arc.archive->donotflush);
03018 }
03019 /* }}} */
03020 
03021 /* {{{ proto bool Phar::stopBuffering()
03022  * Saves the contents of a modified archive to disk.
03023  */
03024 PHP_METHOD(Phar, stopBuffering)
03025 {
03026        char *error;
03027 
03028        PHAR_ARCHIVE_OBJECT();
03029        
03030        if (zend_parse_parameters_none() == FAILURE) {
03031               return;
03032        }
03033 
03034        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03035               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03036                      "Cannot write out phar archive, phar is read-only");
03037               return;
03038        }
03039 
03040        phar_obj->arc.archive->donotflush = 0;
03041        phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03042 
03043        if (error) {
03044               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03045               efree(error);
03046        }
03047 }
03048 /* }}} */
03049 
03050 /* {{{ proto bool Phar::setStub(string|stream stub [, int len])
03051  * Change the stub in a phar, phar.tar or phar.zip archive to something other
03052  * than the default. The stub *must* end with a call to __HALT_COMPILER().
03053  */
03054 PHP_METHOD(Phar, setStub)
03055 {
03056        zval *zstub;
03057        char *stub, *error;
03058        int stub_len;
03059        long len = -1;
03060        php_stream *stream;
03061        PHAR_ARCHIVE_OBJECT();
03062 
03063        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03064               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03065                      "Cannot change stub, phar is read-only");
03066               return;
03067        }
03068 
03069        if (phar_obj->arc.archive->is_data) {
03070               if (phar_obj->arc.archive->is_tar) {
03071                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03072                             "A Phar stub cannot be set in a plain tar archive");
03073               } else {
03074                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03075                             "A Phar stub cannot be set in a plain zip archive");
03076               }
03077               return;
03078        }
03079 
03080        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zstub, &len) == SUCCESS) {
03081               if ((php_stream_from_zval_no_verify(stream, &zstub)) != NULL) {
03082                      if (len > 0) {
03083                             len = -len;
03084                      } else {
03085                             len = -1;
03086                      }
03087                      if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03088                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03089                             return;
03090                      }
03091                      phar_flush(phar_obj->arc.archive, (char *) &zstub, len, 0, &error TSRMLS_CC);
03092                      if (error) {
03093                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03094                             efree(error);
03095                      }
03096                      RETURN_TRUE;
03097               } else {
03098                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03099                             "Cannot change stub, unable to read from input stream");
03100               }
03101        } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) {
03102               if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03103                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03104                      return;
03105               }
03106               phar_flush(phar_obj->arc.archive, stub, stub_len, 0, &error TSRMLS_CC);
03107 
03108               if (error) {
03109                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03110                      efree(error);
03111               }
03112 
03113               RETURN_TRUE;
03114        }
03115 
03116        RETURN_FALSE;
03117 }
03118 /* }}} */
03119 
03120 /* {{{ proto bool Phar::setDefaultStub([string index[, string webindex]])
03121  * In a pure phar archive, sets a stub that can be used to run the archive
03122  * regardless of whether the phar extension is available. The first parameter
03123  * is the CLI startup filename, which defaults to "index.php". The second
03124  * parameter is the web startup filename and also defaults to "index.php"
03125  * (falling back to CLI behaviour).
03126  * Both parameters are optional.
03127  * In a phar.zip or phar.tar archive, the default stub is used only to
03128  * identify the archive to the extension as a Phar object. This allows the
03129  * extension to treat phar.zip and phar.tar types as honorary phars. Since
03130  * files cannot be loaded via this kind of stub, no parameters are accepted
03131  * when the Phar object is zip- or tar-based.
03132  */
03133 PHP_METHOD(Phar, setDefaultStub)
03134 {
03135        char *index = NULL, *webindex = NULL, *error = NULL, *stub = NULL;
03136        int index_len = 0, webindex_len = 0, created_stub = 0;
03137        size_t stub_len = 0;
03138        PHAR_ARCHIVE_OBJECT();
03139 
03140        if (phar_obj->arc.archive->is_data) {
03141               if (phar_obj->arc.archive->is_tar) {
03142                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03143                             "A Phar stub cannot be set in a plain tar archive");
03144               } else {
03145                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03146                             "A Phar stub cannot be set in a plain zip archive");
03147               }
03148               return;
03149        }
03150 
03151        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
03152               RETURN_FALSE;
03153        }
03154 
03155        if (ZEND_NUM_ARGS() > 0 && (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip)) {
03156               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());
03157               RETURN_FALSE;
03158        }
03159 
03160        if (PHAR_G(readonly)) {
03161               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03162                      "Cannot change stub: phar.readonly=1");
03163               RETURN_FALSE;
03164        }
03165 
03166        if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) {
03167               stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
03168 
03169               if (error) {
03170                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "%s", error);
03171                      efree(error);
03172                      if (stub) {
03173                             efree(stub);
03174                      }
03175                      RETURN_FALSE;
03176               }
03177 
03178               created_stub = 1;
03179        }
03180 
03181        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03182               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03183               return;
03184        }
03185        phar_flush(phar_obj->arc.archive, stub, stub_len, 1, &error TSRMLS_CC);
03186 
03187        if (created_stub) {
03188               efree(stub);
03189        }
03190 
03191        if (error) {
03192               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03193               efree(error);
03194               RETURN_FALSE;
03195        }
03196 
03197        RETURN_TRUE;
03198 }
03199 /* }}} */
03200 
03201 /* {{{ proto array Phar::setSignatureAlgorithm(int sigtype[, string privatekey])
03202  * Sets the signature algorithm for a phar and applies it. The signature
03203  * algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256,
03204  * Phar::SHA512, or Phar::OPENSSL. Note that zip- based phar archives
03205  * cannot support signatures.
03206  */
03207 PHP_METHOD(Phar, setSignatureAlgorithm)
03208 {
03209        long algo;
03210        char *error, *key = NULL;
03211        int key_len = 0;
03212 
03213        PHAR_ARCHIVE_OBJECT();
03214 
03215        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03216               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03217                      "Cannot set signature algorithm, phar is read-only");
03218               return;
03219        }
03220 
03221        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &algo, &key, &key_len) != SUCCESS) {
03222               return;
03223        }
03224 
03225        switch (algo) {
03226               case PHAR_SIG_SHA256:
03227               case PHAR_SIG_SHA512:
03228 #ifndef PHAR_HASH_OK
03229                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03230                             "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled and built non-shared");
03231                      return;
03232 #endif
03233               case PHAR_SIG_MD5:
03234               case PHAR_SIG_SHA1:
03235               case PHAR_SIG_OPENSSL:
03236                      if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03237                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03238                             return;
03239                      }
03240                      phar_obj->arc.archive->sig_flags = algo;
03241                      phar_obj->arc.archive->is_modified = 1;
03242                      PHAR_G(openssl_privatekey) = key;
03243                      PHAR_G(openssl_privatekey_len) = key_len;
03244 
03245                      phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03246                      if (error) {
03247                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03248                             efree(error);
03249                      }
03250                      break;
03251               default:
03252                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03253                             "Unknown signature algorithm specified");
03254        }
03255 }
03256 /* }}} */
03257 
03258 /* {{{ proto array|false Phar::getSignature()
03259  * Returns a hash signature, or FALSE if the archive is unsigned.
03260  */
03261 PHP_METHOD(Phar, getSignature)
03262 {
03263        PHAR_ARCHIVE_OBJECT();
03264        
03265        if (zend_parse_parameters_none() == FAILURE) {
03266               return;
03267        }
03268 
03269        if (phar_obj->arc.archive->signature) {
03270               char *unknown;
03271               int unknown_len;
03272 
03273               array_init(return_value);
03274               add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1);
03275               switch(phar_obj->arc.archive->sig_flags) {
03276                      case PHAR_SIG_MD5:
03277                             add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1);
03278                             break;
03279                      case PHAR_SIG_SHA1:
03280                             add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1);
03281                             break;
03282                      case PHAR_SIG_SHA256:
03283                             add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1);
03284                             break;
03285                      case PHAR_SIG_SHA512:
03286                             add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1);
03287                             break;
03288                      case PHAR_SIG_OPENSSL:
03289                             add_assoc_stringl(return_value, "hash_type", "OpenSSL", 7, 1);
03290                             break;
03291                      default:
03292                             unknown_len = spprintf(&unknown, 0, "Unknown (%u)", phar_obj->arc.archive->sig_flags);
03293                             add_assoc_stringl(return_value, "hash_type", unknown, unknown_len, 0);
03294                             break;
03295               }
03296        } else {
03297               RETURN_FALSE;
03298        }
03299 }
03300 /* }}} */
03301 
03302 /* {{{ proto bool Phar::getModified()
03303  * Return whether phar was modified
03304  */
03305 PHP_METHOD(Phar, getModified)
03306 {
03307        PHAR_ARCHIVE_OBJECT();
03308        
03309        if (zend_parse_parameters_none() == FAILURE) {
03310               return;
03311        }
03312 
03313        RETURN_BOOL(phar_obj->arc.archive->is_modified);
03314 }
03315 /* }}} */
03316 
03317 static int phar_set_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
03318 {
03319        phar_entry_info *entry = (phar_entry_info *)pDest;
03320        php_uint32 compress = *(php_uint32 *)argument;
03321 
03322        if (entry->is_deleted) {
03323               return ZEND_HASH_APPLY_KEEP;
03324        }
03325 
03326        entry->old_flags = entry->flags;
03327        entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
03328        entry->flags |= compress;
03329        entry->is_modified = 1;
03330        return ZEND_HASH_APPLY_KEEP;
03331 }
03332 /* }}} */
03333 
03334 static int phar_test_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
03335 {
03336        phar_entry_info *entry = (phar_entry_info *)pDest;
03337 
03338        if (entry->is_deleted) {
03339               return ZEND_HASH_APPLY_KEEP;
03340        }
03341 
03342        if (!PHAR_G(has_bz2)) {
03343               if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
03344                      *(int *) argument = 0;
03345               }
03346        }
03347 
03348        if (!PHAR_G(has_zlib)) {
03349               if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
03350                      *(int *) argument = 0;
03351               }
03352        }
03353 
03354        return ZEND_HASH_APPLY_KEEP;
03355 }
03356 /* }}} */
03357 
03358 static void pharobj_set_compression(HashTable *manifest, php_uint32 compress TSRMLS_DC) /* {{{ */
03359 {
03360        zend_hash_apply_with_argument(manifest, phar_set_compression, &compress TSRMLS_CC);
03361 }
03362 /* }}} */
03363 
03364 static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */
03365 {
03366        int test;
03367 
03368        test = 1;
03369        zend_hash_apply_with_argument(manifest, phar_test_compression, &test TSRMLS_CC);
03370        return test;
03371 }
03372 /* }}} */
03373 
03374 /* {{{ proto object Phar::compress(int method[, string extension])
03375  * Compress a .tar, or .phar.tar with whole-file compression
03376  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
03377  * the kind of compression desired
03378  */
03379 PHP_METHOD(Phar, compress)
03380 {
03381        long method;
03382        char *ext = NULL;
03383        int ext_len = 0;
03384        php_uint32 flags;
03385        zval *ret;
03386        PHAR_ARCHIVE_OBJECT();
03387 
03388        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &method, &ext, &ext_len) == FAILURE) {
03389               return;
03390        }
03391 
03392        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03393               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03394                      "Cannot compress phar archive, phar is read-only");
03395               return;
03396        }
03397 
03398        if (phar_obj->arc.archive->is_zip) {
03399               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03400                      "Cannot compress zip-based archives with whole-archive compression");
03401               return;
03402        }
03403 
03404        switch (method) {
03405               case 0:
03406                      flags = PHAR_FILE_COMPRESSED_NONE;
03407                      break;
03408               case PHAR_ENT_COMPRESSED_GZ:
03409                      if (!PHAR_G(has_zlib)) {
03410                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03411                                    "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
03412                             return;
03413                      }
03414                      flags = PHAR_FILE_COMPRESSED_GZ;
03415                      break;
03416 
03417               case PHAR_ENT_COMPRESSED_BZ2:
03418                      if (!PHAR_G(has_bz2)) {
03419                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03420                                    "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
03421                             return;
03422                      }
03423                      flags = PHAR_FILE_COMPRESSED_BZ2;
03424                      break;
03425               default:
03426                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03427                             "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
03428                      return;
03429        }
03430 
03431        if (phar_obj->arc.archive->is_tar) {
03432               ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, flags TSRMLS_CC);
03433        } else {
03434               ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, flags TSRMLS_CC);
03435        }
03436 
03437        if (ret) {
03438               RETURN_ZVAL(ret, 1, 1);
03439        } else {
03440               RETURN_NULL();
03441        }
03442 }
03443 /* }}} */
03444 
03445 /* {{{ proto object Phar::decompress([string extension])
03446  * Decompress a .tar, or .phar.tar with whole-file compression
03447  */
03448 PHP_METHOD(Phar, decompress)
03449 {
03450        char *ext = NULL;
03451        int ext_len = 0;
03452        zval *ret;
03453        PHAR_ARCHIVE_OBJECT();
03454 
03455        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ext, &ext_len) == FAILURE) {
03456               return;
03457        }
03458 
03459        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03460               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03461                      "Cannot decompress phar archive, phar is read-only");
03462               return;
03463        }
03464 
03465        if (phar_obj->arc.archive->is_zip) {
03466               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03467                      "Cannot decompress zip-based archives with whole-archive compression");
03468               return;
03469        }
03470 
03471        if (phar_obj->arc.archive->is_tar) {
03472               ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
03473        } else {
03474               ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
03475        }
03476 
03477        if (ret) {
03478               RETURN_ZVAL(ret, 1, 1);
03479        } else {
03480               RETURN_NULL();
03481        }
03482 }
03483 /* }}} */
03484 
03485 /* {{{ proto object Phar::compressFiles(int method)
03486  * Compress all files within a phar or zip archive using the specified compression
03487  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
03488  * the kind of compression desired
03489  */
03490 PHP_METHOD(Phar, compressFiles)
03491 {
03492        char *error;
03493        php_uint32 flags;
03494        long method;
03495        PHAR_ARCHIVE_OBJECT();
03496 
03497        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
03498               return;
03499        }
03500 
03501        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03502               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03503                      "Phar is readonly, cannot change compression");
03504               return;
03505        }
03506 
03507        switch (method) {
03508               case PHAR_ENT_COMPRESSED_GZ:
03509                      if (!PHAR_G(has_zlib)) {
03510                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03511                                    "Cannot compress files within archive with gzip, enable ext/zlib in php.ini");
03512                             return;
03513                      }
03514                      flags = PHAR_ENT_COMPRESSED_GZ;
03515                      break;
03516 
03517               case PHAR_ENT_COMPRESSED_BZ2:
03518                      if (!PHAR_G(has_bz2)) {
03519                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03520                                    "Cannot compress files within archive with bz2, enable ext/bz2 in php.ini");
03521                             return;
03522                      }
03523                      flags = PHAR_ENT_COMPRESSED_BZ2;
03524                      break;
03525               default:
03526                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03527                             "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
03528                      return;
03529        }
03530 
03531        if (phar_obj->arc.archive->is_tar) {
03532               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03533                      "Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive");
03534               return;
03535        }
03536 
03537        if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
03538               if (flags == PHAR_FILE_COMPRESSED_GZ) {
03539                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03540                             "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed");
03541               } else {
03542                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03543                             "Cannot compress all files as Bzip2, some are compressed as gzip and cannot be decompressed");
03544               }
03545               return;
03546        }
03547 
03548        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03549               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03550               return;
03551        }
03552        pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC);
03553        phar_obj->arc.archive->is_modified = 1;
03554        phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03555 
03556        if (error) {
03557               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s", error);
03558               efree(error);
03559        }
03560 }
03561 /* }}} */
03562 
03563 /* {{{ proto bool Phar::decompressFiles()
03564  * decompress every file
03565  */
03566 PHP_METHOD(Phar, decompressFiles)
03567 {
03568        char *error;
03569        PHAR_ARCHIVE_OBJECT();
03570        
03571        if (zend_parse_parameters_none() == FAILURE) {
03572               return;
03573        }
03574 
03575        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03576               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03577                      "Phar is readonly, cannot change compression");
03578               return;
03579        }
03580 
03581        if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
03582               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
03583                      "Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed");
03584               return;
03585        }
03586 
03587        if (phar_obj->arc.archive->is_tar) {
03588               RETURN_TRUE;
03589        } else {
03590               if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03591                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03592                      return;
03593               }
03594               pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_NONE TSRMLS_CC);
03595        }
03596 
03597        phar_obj->arc.archive->is_modified = 1;
03598        phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03599 
03600        if (error) {
03601               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s", error);
03602               efree(error);
03603        }
03604 
03605        RETURN_TRUE;
03606 }
03607 /* }}} */
03608 
03609 /* {{{ proto bool Phar::copy(string oldfile, string newfile)
03610  * copy a file internal to the phar archive to another new file within the phar
03611  */
03612 PHP_METHOD(Phar, copy)
03613 {
03614        char *oldfile, *newfile, *error;
03615        const char *pcr_error;
03616        int oldfile_len, newfile_len;
03617        phar_entry_info *oldentry, newentry = {0}, *temp;
03618 
03619        PHAR_ARCHIVE_OBJECT();
03620 
03621        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) {
03622               return;
03623        }
03624 
03625        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03626               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03627                      "Cannot copy \"%s\" to \"%s\", phar is read-only", oldfile, newfile);
03628               RETURN_FALSE;
03629        }
03630 
03631        if (oldfile_len >= sizeof(".phar")-1 && !memcmp(oldfile, ".phar", sizeof(".phar")-1)) {
03632               /* can't copy a meta file */
03633               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03634                      "file \"%s\" cannot be copied to file \"%s\", cannot copy Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname);
03635               RETURN_FALSE;
03636        }
03637 
03638        if (newfile_len >= sizeof(".phar")-1 && !memcmp(newfile, ".phar", sizeof(".phar")-1)) {
03639               /* can't copy a meta file */
03640               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03641                      "file \"%s\" cannot be copied to file \"%s\", cannot copy to Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname);
03642               RETURN_FALSE;
03643        }
03644 
03645        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) {
03646               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03647                      "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->arc.archive->fname);
03648               RETURN_FALSE;
03649        }
03650 
03651        if (zend_hash_exists(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len)) {
03652               if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len, (void**)&temp) || !temp->is_deleted) {
03653                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03654                             "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->arc.archive->fname);
03655                      RETURN_FALSE;
03656               }
03657        }
03658 
03659        if (phar_path_check(&newfile, &newfile_len, &pcr_error) > pcr_is_ok) {
03660               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
03661                             "file \"%s\" contains invalid characters %s, cannot be copied from \"%s\" in phar %s", newfile, pcr_error, oldfile, phar_obj->arc.archive->fname);
03662               RETURN_FALSE;
03663        }
03664 
03665        if (phar_obj->arc.archive->is_persistent) {
03666               if (FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03667                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03668                      return;
03669               }
03670               /* re-populate with copied-on-write entry */
03671               zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry);
03672        }
03673 
03674        memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info));
03675 
03676        if (newentry.metadata) {
03677               zval *t;
03678 
03679               t = newentry.metadata;
03680               ALLOC_ZVAL(newentry.metadata);
03681               *newentry.metadata = *t;
03682               zval_copy_ctor(newentry.metadata);
03683 #if PHP_VERSION_ID < 50300
03684               newentry.metadata->refcount = 1;
03685 #else
03686               Z_SET_REFCOUNT_P(newentry.metadata, 1);
03687 #endif
03688 
03689               newentry.metadata_str.c = NULL;
03690               newentry.metadata_str.len = 0;
03691        }
03692 
03693        newentry.filename = estrndup(newfile, newfile_len);
03694        newentry.filename_len = newfile_len;
03695        newentry.fp_refcount = 0;
03696 
03697        if (oldentry->fp_type != PHAR_FP) {
03698               if (FAILURE == phar_copy_entry_fp(oldentry, &newentry, &error TSRMLS_CC)) {
03699                      efree(newentry.filename);
03700                      php_stream_close(newentry.fp);
03701                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03702                      efree(error);
03703                      return;
03704               }
03705        }
03706 
03707        zend_hash_add(&oldentry->phar->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
03708        phar_obj->arc.archive->is_modified = 1;
03709        phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03710 
03711        if (error) {
03712               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03713               efree(error);
03714        }
03715 
03716        RETURN_TRUE;
03717 }
03718 /* }}} */
03719 
03720 /* {{{ proto int Phar::offsetExists(string entry)
03721  * determines whether a file exists in the phar
03722  */
03723 PHP_METHOD(Phar, offsetExists)
03724 {
03725        char *fname;
03726        int fname_len;
03727        phar_entry_info *entry;
03728 
03729        PHAR_ARCHIVE_OBJECT();
03730 
03731        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
03732               return;
03733        }
03734 
03735        if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
03736               if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
03737                      if (entry->is_deleted) {
03738                             /* entry is deleted, but has not been flushed to disk yet */
03739                             RETURN_FALSE;
03740                      }
03741               }
03742 
03743               if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
03744                      /* none of these are real files, so they don't exist */
03745                      RETURN_FALSE;
03746               }
03747               RETURN_TRUE;
03748        } else {
03749               if (zend_hash_exists(&phar_obj->arc.archive->virtual_dirs, fname, (uint) fname_len)) {
03750                      RETURN_TRUE;
03751               }
03752               RETURN_FALSE;
03753        }
03754 }
03755 /* }}} */
03756 
03757 /* {{{ proto int Phar::offsetGet(string entry)
03758  * get a PharFileInfo object for a specific file
03759  */
03760 PHP_METHOD(Phar, offsetGet)
03761 {
03762        char *fname, *error;
03763        int fname_len;
03764        zval *zfname;
03765        phar_entry_info *entry;
03766        PHAR_ARCHIVE_OBJECT();
03767 
03768        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
03769               return;
03770        }
03771 
03772        /* security is 0 here so that we can get a better error message than "entry doesn't exist" */
03773        if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error, 0 TSRMLS_CC))) {
03774               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:"");
03775        } else {
03776               if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
03777                      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);
03778                      return;
03779               }
03780 
03781               if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
03782                      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);
03783                      return;
03784               }
03785 
03786               if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
03787                      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);
03788                      return;
03789               }
03790 
03791               if (entry->is_temp_dir) {
03792                      efree(entry->filename);
03793                      efree(entry);
03794               }
03795 
03796               fname_len = spprintf(&fname, 0, "phar://%s/%s", phar_obj->arc.archive->fname, fname);
03797               MAKE_STD_ZVAL(zfname);
03798               ZVAL_STRINGL(zfname, fname, fname_len, 0);
03799               spl_instantiate_arg_ex1(phar_obj->spl.info_class, &return_value, 0, zfname TSRMLS_CC);
03800               zval_ptr_dtor(&zfname);
03801        }
03802 }
03803 /* }}} */
03804 
03805 /* {{{ add a file within the phar archive from a string or resource
03806  */
03807 static void phar_add_file(phar_archive_data **pphar, char *filename, int filename_len, char *cont_str, int cont_len, zval *zresource TSRMLS_DC)
03808 {
03809        char *error;
03810        size_t contents_len;
03811        phar_entry_data *data;
03812        php_stream *contents_file;
03813 
03814        if (filename_len >= sizeof(".phar")-1 && !memcmp(filename, ".phar", sizeof(".phar")-1)) {
03815               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create any files in magic \".phar\" directory", (*pphar)->fname);
03816               return;
03817        }
03818 
03819        if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, filename, filename_len, "w+b", 0, &error, 1 TSRMLS_CC))) {
03820               if (error) {
03821                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created: %s", filename, error);
03822                      efree(error);
03823               } else {
03824                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created", filename);
03825               }
03826               return;
03827        } else {
03828               if (error) {
03829                      efree(error);
03830               }
03831 
03832               if (!data->internal_file->is_dir) {
03833                      if (cont_str) {
03834                             contents_len = php_stream_write(data->fp, cont_str, cont_len);
03835                             if (contents_len != cont_len) {
03836                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
03837                                    return;
03838                             }
03839                      } else {
03840                             if (!(php_stream_from_zval_no_verify(contents_file, &zresource))) {
03841                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
03842                                    return;
03843                             }
03844                             phar_stream_copy_to_stream(contents_file, data->fp, PHP_STREAM_COPY_ALL, &contents_len);
03845                      }
03846 
03847                      data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
03848               }
03849 
03850               /* check for copy-on-write */
03851               if (pphar[0] != data->phar) {
03852                      *pphar = data->phar;
03853               }
03854               phar_entry_delref(data TSRMLS_CC);
03855               phar_flush(*pphar, 0, 0, 0, &error TSRMLS_CC);
03856 
03857               if (error) {
03858                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03859                      efree(error);
03860               }
03861        }
03862 }
03863 /* }}} */
03864 
03865 /* {{{ create a directory within the phar archive
03866  */
03867 static void phar_mkdir(phar_archive_data **pphar, char *dirname, int dirname_len TSRMLS_DC)
03868 {
03869        char *error;
03870        phar_entry_data *data;
03871 
03872        if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, dirname, dirname_len, "w+b", 2, &error, 1 TSRMLS_CC))) {
03873               if (error) {
03874                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created: %s", dirname, error);
03875                      efree(error);
03876               } else {
03877                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created", dirname);
03878               }
03879 
03880               return;
03881        } else {
03882               if (error) {
03883                      efree(error);
03884               }
03885 
03886               /* check for copy on write */
03887               if (data->phar != *pphar) {
03888                      *pphar = data->phar;
03889               }
03890               phar_entry_delref(data TSRMLS_CC);
03891               phar_flush(*pphar, 0, 0, 0, &error TSRMLS_CC);
03892 
03893               if (error) {
03894                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03895                      efree(error);
03896               }
03897        }
03898 }
03899 /* }}} */
03900 
03901 /* {{{ proto int Phar::offsetSet(string entry, string value)
03902  * set the contents of an internal file to those of an external file
03903  */
03904 PHP_METHOD(Phar, offsetSet)
03905 {
03906        char *fname, *cont_str = NULL;
03907        int fname_len, cont_len;
03908        zval *zresource;
03909        PHAR_ARCHIVE_OBJECT();
03910 
03911        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03912               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
03913               return;
03914        }
03915 
03916        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sr", &fname, &fname_len, &zresource) == FAILURE
03917        && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) {
03918               return;
03919        }
03920 
03921        if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
03922               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);
03923               return;
03924        }
03925 
03926        if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
03927               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);
03928               return;
03929        }
03930 
03931        if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
03932               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);
03933               return;
03934        }
03935 
03936        phar_add_file(&(phar_obj->arc.archive), fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC);
03937 }
03938 /* }}} */
03939 
03940 /* {{{ proto int Phar::offsetUnset(string entry)
03941  * remove a file from a phar
03942  */
03943 PHP_METHOD(Phar, offsetUnset)
03944 {
03945        char *fname, *error;
03946        int fname_len;
03947        phar_entry_info *entry;
03948        PHAR_ARCHIVE_OBJECT();
03949 
03950        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
03951               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
03952               return;
03953        }
03954 
03955        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
03956               return;
03957        }
03958 
03959        if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
03960               if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
03961                      if (entry->is_deleted) {
03962                             /* entry is deleted, but has not been flushed to disk yet */
03963                             return;
03964                      }
03965 
03966                      if (phar_obj->arc.archive->is_persistent) {
03967                             if (FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
03968                                    zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
03969                                    return;
03970                             }
03971                             /* re-populate entry after copy on write */
03972                             zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void **)&entry);
03973                      }
03974                      entry->is_modified = 0;
03975                      entry->is_deleted = 1;
03976                      /* we need to "flush" the stream to save the newly deleted file on disk */
03977                      phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
03978 
03979                      if (error) {
03980                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
03981                             efree(error);
03982                      }
03983 
03984                      RETURN_TRUE;
03985               }
03986        } else {
03987               RETURN_FALSE;
03988        }
03989 }
03990 /* }}} */
03991 
03992 /* {{{ proto string Phar::addEmptyDir(string dirname)
03993  * Adds an empty directory to the phar archive
03994  */
03995 PHP_METHOD(Phar, addEmptyDir)
03996 {
03997        char *dirname;
03998        int dirname_len;
03999 
04000        PHAR_ARCHIVE_OBJECT();
04001 
04002        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dirname, &dirname_len) == FAILURE) {
04003               return;
04004        }
04005 
04006        if (dirname_len >= sizeof(".phar")-1 && !memcmp(dirname, ".phar", sizeof(".phar")-1)) {
04007               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create a directory in magic \".phar\" directory");
04008               return;
04009        }
04010 
04011        phar_mkdir(&phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC);
04012 }
04013 /* }}} */
04014 
04015 /* {{{ proto string Phar::addFile(string filename[, string localname])
04016  * Adds a file to the archive using the filename, or the second parameter as the name within the archive
04017  */
04018 PHP_METHOD(Phar, addFile)
04019 {
04020        char *fname, *localname = NULL;
04021        int fname_len, localname_len = 0;
04022        php_stream *resource;
04023        zval *zresource;
04024 
04025        PHAR_ARCHIVE_OBJECT();
04026 
04027        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) {
04028               return;
04029        }
04030 
04031 #if PHP_API_VERSION < 20100412
04032        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
04033               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);
04034               return;
04035        }
04036 #endif
04037 
04038        if (!strstr(fname, "://") && php_check_open_basedir(fname TSRMLS_CC)) {
04039               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);
04040               return;
04041        }
04042 
04043        if (!(resource = php_stream_open_wrapper(fname, "rb", 0, NULL))) {
04044               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive", fname);
04045               return;
04046        }
04047 
04048        if (localname) {
04049               fname = localname;
04050               fname_len = localname_len;
04051        }
04052 
04053        MAKE_STD_ZVAL(zresource);
04054        php_stream_to_zval(resource, zresource);
04055        phar_add_file(&(phar_obj->arc.archive), fname, fname_len, NULL, 0, zresource TSRMLS_CC);
04056        efree(zresource);
04057        php_stream_close(resource);
04058 }
04059 /* }}} */
04060 
04061 /* {{{ proto string Phar::addFromString(string localname, string contents)
04062  * Adds a file to the archive using its contents as a string
04063  */
04064 PHP_METHOD(Phar, addFromString)
04065 {
04066        char *localname, *cont_str;
04067        int localname_len, cont_len;
04068 
04069        PHAR_ARCHIVE_OBJECT();
04070 
04071        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) {
04072               return;
04073        }
04074 
04075        phar_add_file(&(phar_obj->arc.archive), localname, localname_len, cont_str, cont_len, NULL TSRMLS_CC);
04076 }
04077 /* }}} */
04078 
04079 /* {{{ proto string Phar::getStub()
04080  * Returns the stub at the head of a phar archive as a string.
04081  */
04082 PHP_METHOD(Phar, getStub)
04083 {
04084        size_t len;
04085        char *buf;
04086        php_stream *fp;
04087        php_stream_filter *filter = NULL;
04088        phar_entry_info *stub;
04089 
04090        PHAR_ARCHIVE_OBJECT();
04091        
04092        if (zend_parse_parameters_none() == FAILURE) {
04093               return;
04094        }
04095 
04096        if (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) {
04097 
04098               if (SUCCESS == zend_hash_find(&(phar_obj->arc.archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
04099                      if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew && !(stub->flags & PHAR_ENT_COMPRESSION_MASK)) {
04100                             fp = phar_obj->arc.archive->fp;
04101                      } else {
04102                             if (!(fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL))) {
04103                                    zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "phar error: unable to open phar \"%s\"", phar_obj->arc.archive->fname);
04104                                    return;
04105                             }
04106                             if (stub->flags & PHAR_ENT_COMPRESSION_MASK) {
04107                                    char *filter_name;
04108 
04109                                    if ((filter_name = phar_decompress_filter(stub, 0)) != NULL) {
04110                                           filter = php_stream_filter_create(filter_name, NULL, php_stream_is_persistent(fp) TSRMLS_CC);
04111                                    } else {
04112                                           filter = NULL;
04113                                    }
04114                                    if (!filter) {
04115                                           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));
04116                                           return;
04117                                    }
04118                                    php_stream_filter_append(&fp->readfilters, filter);
04119                             }
04120                      }
04121 
04122                      if (!fp)  {
04123                             zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04124                                    "Unable to read stub");
04125                             return;
04126                      }
04127 
04128                      php_stream_seek(fp, stub->offset_abs, SEEK_SET);
04129                      len = stub->uncompressed_filesize;
04130                      goto carry_on;
04131               } else {
04132                      RETURN_STRINGL("", 0, 1);
04133               }
04134        }
04135        len = phar_obj->arc.archive->halt_offset;
04136 
04137        if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) {
04138               fp = phar_obj->arc.archive->fp;
04139        } else {
04140               fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL);
04141        }
04142 
04143        if (!fp)  {
04144               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04145                      "Unable to read stub");
04146               return;
04147        }
04148 
04149        php_stream_rewind(fp);
04150 carry_on:
04151        buf = safe_emalloc(len, 1, 1);
04152 
04153        if (len != php_stream_read(fp, buf, len)) {
04154               if (fp != phar_obj->arc.archive->fp) {
04155                      php_stream_close(fp);
04156               }
04157               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04158                      "Unable to read stub");
04159               efree(buf);
04160               return;
04161        }
04162 
04163        if (filter) {
04164               php_stream_filter_flush(filter, 1);
04165               php_stream_filter_remove(filter, 1 TSRMLS_CC);
04166        }
04167 
04168        if (fp != phar_obj->arc.archive->fp) {
04169               php_stream_close(fp);
04170        }
04171 
04172        buf[len] = '\0';
04173        RETURN_STRINGL(buf, len, 0);
04174 }
04175 /* }}}*/
04176 
04177 /* {{{ proto int Phar::hasMetaData()
04178  * Returns TRUE if the phar has global metadata, FALSE otherwise.
04179  */
04180 PHP_METHOD(Phar, hasMetadata)
04181 {
04182        PHAR_ARCHIVE_OBJECT();
04183 
04184        RETURN_BOOL(phar_obj->arc.archive->metadata != NULL);
04185 }
04186 /* }}} */
04187 
04188 /* {{{ proto int Phar::getMetaData()
04189  * Returns the global metadata of the phar
04190  */
04191 PHP_METHOD(Phar, getMetadata)
04192 {
04193        PHAR_ARCHIVE_OBJECT();
04194        
04195        if (zend_parse_parameters_none() == FAILURE) {
04196               return;
04197        }
04198 
04199        if (phar_obj->arc.archive->metadata) {
04200               if (phar_obj->arc.archive->is_persistent) {
04201                      zval *ret;
04202                      char *buf = estrndup((char *) phar_obj->arc.archive->metadata, phar_obj->arc.archive->metadata_len);
04203                      /* assume success, we would have failed before */
04204                      phar_parse_metadata(&buf, &ret, phar_obj->arc.archive->metadata_len TSRMLS_CC);
04205                      efree(buf);
04206                      RETURN_ZVAL(ret, 0, 1);
04207               }
04208               RETURN_ZVAL(phar_obj->arc.archive->metadata, 1, 0);
04209        }
04210 }
04211 /* }}} */
04212 
04213 /* {{{ proto int Phar::setMetaData(mixed $metadata)
04214  * Sets the global metadata of the phar
04215  */
04216 PHP_METHOD(Phar, setMetadata)
04217 {
04218        char *error;
04219        zval *metadata;
04220 
04221        PHAR_ARCHIVE_OBJECT();
04222 
04223        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
04224               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
04225               return;
04226        }
04227 
04228        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
04229               return;
04230        }
04231 
04232        if (phar_obj->arc.archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->arc.archive) TSRMLS_CC)) {
04233               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar_obj->arc.archive->fname);
04234               return;
04235        }
04236        if (phar_obj->arc.archive->metadata) {
04237               zval_ptr_dtor(&phar_obj->arc.archive->metadata);
04238               phar_obj->arc.archive->metadata = NULL;
04239        }
04240 
04241        MAKE_STD_ZVAL(phar_obj->arc.archive->metadata);
04242        ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0);
04243        phar_obj->arc.archive->is_modified = 1;
04244        phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
04245 
04246        if (error) {
04247               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
04248               efree(error);
04249        }
04250 }
04251 /* }}} */
04252 
04253 /* {{{ proto int Phar::delMetadata()
04254  * Deletes the global metadata of the phar
04255  */
04256 PHP_METHOD(Phar, delMetadata)
04257 {
04258        char *error;
04259 
04260        PHAR_ARCHIVE_OBJECT();
04261 
04262        if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
04263               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
04264               return;
04265        }
04266 
04267        if (phar_obj->arc.archive->metadata) {
04268               zval_ptr_dtor(&phar_obj->arc.archive->metadata);
04269               phar_obj->arc.archive->metadata = NULL;
04270               phar_obj->arc.archive->is_modified = 1;
04271               phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
04272 
04273               if (error) {
04274                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
04275                      efree(error);
04276                      RETURN_FALSE;
04277               } else {
04278                      RETURN_TRUE;
04279               }
04280 
04281        } else {
04282               RETURN_TRUE;
04283        }
04284 }
04285 /* }}} */
04286 #if PHP_API_VERSION < 20100412
04287 #define PHAR_OPENBASEDIR_CHECKPATH(filename) \
04288        (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
04289 #else
04290 #define PHAR_OPENBASEDIR_CHECKPATH(filename) \
04291        php_check_open_basedir(filename TSRMLS_CC)
04292 #endif
04293 
04294 static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC) /* {{{ */
04295 {
04296        php_stream_statbuf ssb;
04297        int len;
04298        php_stream *fp;
04299        char *fullpath, *slash;
04300        mode_t mode;
04301 
04302        if (entry->is_mounted) {
04303               /* silently ignore mounted entries */
04304               return SUCCESS;
04305        }
04306 
04307        if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) {
04308               return SUCCESS;
04309        }
04310 
04311        len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename);
04312 
04313        if (len >= MAXPATHLEN) {
04314               char *tmp;
04315               /* truncate for error message */
04316               fullpath[50] = '\0';
04317               if (entry->filename_len > 50) {
04318                      tmp = estrndup(entry->filename, 50);
04319                      spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, fullpath);
04320                      efree(tmp);
04321               } else {
04322                      spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath);
04323               }
04324               efree(fullpath);
04325               return FAILURE;
04326        }
04327 
04328        if (!len) {
04329               spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
04330               efree(fullpath);
04331               return FAILURE;
04332        }
04333 
04334        if (PHAR_OPENBASEDIR_CHECKPATH(fullpath)) {
04335               spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath);
04336               efree(fullpath);
04337               return FAILURE;
04338        }
04339 
04340        /* let see if the path already exists */
04341        if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) {
04342               spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath);
04343               efree(fullpath);
04344               return FAILURE;
04345        }
04346 
04347        /* perform dirname */
04348        slash = zend_memrchr(entry->filename, '/', entry->filename_len);
04349 
04350        if (slash) {
04351               fullpath[dest_len + (slash - entry->filename) + 1] = '\0';
04352        } else {
04353               fullpath[dest_len] = '\0';
04354        }
04355 
04356        if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
04357               if (entry->is_dir) {
04358                      if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
04359                             spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
04360                             efree(fullpath);
04361                             return FAILURE;
04362                      }
04363               } else {
04364                      if (!php_stream_mkdir(fullpath, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
04365                             spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
04366                             efree(fullpath);
04367                             return FAILURE;
04368                      }
04369               }
04370        }
04371 
04372        if (slash) {
04373               fullpath[dest_len + (slash - entry->filename) + 1] = '/';
04374        } else {
04375               fullpath[dest_len] = '/';
04376        }
04377 
04378        /* it is a standalone directory, job done */
04379        if (entry->is_dir) {
04380               efree(fullpath);
04381               return SUCCESS;
04382        }
04383 
04384 #if PHP_API_VERSION < 20100412
04385        fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
04386 #else
04387        fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS, NULL);
04388 #endif
04389 
04390        if (!fp) {
04391               spprintf(error, 4096, "Cannot extract \"%s\", could not open for writing \"%s\"", entry->filename, fullpath);
04392               efree(fullpath);
04393               return FAILURE;
04394        }
04395 
04396        if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
04397               if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
04398                      if (error) {
04399                             spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
04400                      } else {
04401                             spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", entry->filename, fullpath);
04402                      }
04403                      efree(fullpath);
04404                      php_stream_close(fp);
04405                      return FAILURE;
04406               }
04407        }
04408 
04409        if (FAILURE == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
04410               spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to seek internal file pointer", entry->filename, fullpath);
04411               efree(fullpath);
04412               php_stream_close(fp);
04413               return FAILURE;
04414        }
04415 
04416        if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp, entry->uncompressed_filesize, NULL)) {
04417               spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", copying contents failed", entry->filename, fullpath);
04418               efree(fullpath);
04419               php_stream_close(fp);
04420               return FAILURE;
04421        }
04422 
04423        php_stream_close(fp);
04424        mode = (mode_t) entry->flags & PHAR_ENT_PERM_MASK;
04425 
04426        if (FAILURE == VCWD_CHMOD(fullpath, mode)) {
04427               spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", setting file permissions failed", entry->filename, fullpath);
04428               efree(fullpath);
04429               return FAILURE;
04430        }
04431 
04432        efree(fullpath);
04433        return SUCCESS;
04434 }
04435 /* }}} */
04436 
04437 /* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
04438  * Extract one or more file from a phar archive, optionally overwriting existing files
04439  */
04440 PHP_METHOD(Phar, extractTo)
04441 {
04442        char *error = NULL;
04443        php_stream *fp;
04444        php_stream_statbuf ssb;
04445        phar_entry_info *entry;
04446        char *pathto, *filename, *actual;
04447        int pathto_len, filename_len;
04448        int ret, i;
04449        int nelems;
04450        zval *zval_files = NULL;
04451        zend_bool overwrite = 0;
04452 
04453        PHAR_ARCHIVE_OBJECT();
04454 
04455        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) {
04456               return;
04457        }
04458 
04459        fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
04460 
04461        if (!fp) {
04462               zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
04463                      "Invalid argument, %s cannot be found", phar_obj->arc.archive->fname);
04464               return;
04465        }
04466 
04467        efree(actual);
04468        php_stream_close(fp);
04469 
04470        if (pathto_len < 1) {
04471               zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
04472                      "Invalid argument, extraction path must be non-zero length");
04473               return;
04474        }
04475 
04476        if (pathto_len >= MAXPATHLEN) {
04477               char *tmp = estrndup(pathto, 50);
04478               /* truncate for error message */
04479               zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Cannot extract to \"%s...\", destination directory is too long for filesystem", tmp);
04480               efree(tmp);
04481               return;
04482        }
04483 
04484        if (php_stream_stat_path(pathto, &ssb) < 0) {
04485               ret = php_stream_mkdir(pathto, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL);
04486               if (!ret) {
04487                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04488                             "Unable to create path \"%s\" for extraction", pathto);
04489                      return;
04490               }
04491        } else if (!(ssb.sb.st_mode & S_IFDIR)) {
04492               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04493                      "Unable to use path \"%s\" for extraction, it is a file, must be a directory", pathto);
04494               return;
04495        }
04496 
04497        if (zval_files) {
04498               switch (Z_TYPE_P(zval_files)) {
04499                      case IS_NULL:
04500                             goto all_files;
04501 #if PHP_VERSION_ID >= 60000
04502                      case IS_UNICODE:
04503                             zval_unicode_to_string(zval_files TSRMLS_CC);
04504                             /* break intentionally omitted */
04505 #endif
04506                      case IS_STRING:
04507                             filename = Z_STRVAL_P(zval_files);
04508                             filename_len = Z_STRLEN_P(zval_files);
04509                             break;
04510                      case IS_ARRAY:
04511                             nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files));
04512                             if (nelems == 0 ) {
04513                                    RETURN_FALSE;
04514                             }
04515                             for (i = 0; i < nelems; i++) {
04516                                    zval **zval_file;
04517                                    if (zend_hash_index_find(Z_ARRVAL_P(zval_files), i, (void **) &zval_file) == SUCCESS) {
04518                                           switch (Z_TYPE_PP(zval_file)) {
04519 #if PHP_VERSION_ID >= 60000
04520                                                  case IS_UNICODE:
04521                                                         zval_unicode_to_string(*(zval_file) TSRMLS_CC);
04522                                                         /* break intentionally omitted */
04523 #endif
04524                                                  case IS_STRING:
04525                                                         break;
04526                                                  default:
04527                                                         zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
04528                                                                "Invalid argument, array of filenames to extract contains non-string value");
04529                                                         return;
04530                                           }
04531                                           if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, Z_STRVAL_PP(zval_file), Z_STRLEN_PP(zval_file), (void **)&entry)) {
04532                                                  zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
04533                                                         "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_PP(zval_file), phar_obj->arc.archive->fname);
04534                                           }
04535                                           if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
04536                                                  zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
04537                                                         "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
04538                                                  efree(error);
04539                                                  return;
04540                                           }
04541                                    }
04542                             }
04543                             RETURN_TRUE;
04544                      default:
04545                             zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
04546                                    "Invalid argument, expected a filename (string) or array of filenames");
04547                             return;
04548               }
04549 
04550               if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, filename, filename_len, (void **)&entry)) {
04551                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
04552                             "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->arc.archive->fname);
04553                      return;
04554               }
04555 
04556               if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
04557                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
04558                             "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
04559                      efree(error);
04560                      return;
04561               }
04562        } else {
04563               phar_archive_data *phar;
04564 all_files:
04565               phar = phar_obj->arc.archive;
04566               /* Extract all files */
04567               if (!zend_hash_num_elements(&(phar->manifest))) {
04568                      RETURN_TRUE;
04569               }
04570 
04571               for (zend_hash_internal_pointer_reset(&phar->manifest);
04572               zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
04573               zend_hash_move_forward(&phar->manifest)) {
04574 
04575                      if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
04576                             continue;
04577                      }
04578 
04579                      if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
04580                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
04581                                    "Extraction from phar \"%s\" failed: %s", phar->fname, error);
04582                             efree(error);
04583                             return;
04584                      }
04585               }
04586        }
04587        RETURN_TRUE;
04588 }
04589 /* }}} */
04590 
04591 
04592 /* {{{ proto void PharFileInfo::__construct(string entry)
04593  * Construct a Phar entry object
04594  */
04595 PHP_METHOD(PharFileInfo, __construct)
04596 {
04597        char *fname, *arch, *entry, *error;
04598        int fname_len, arch_len, entry_len;
04599        phar_entry_object *entry_obj;
04600        phar_entry_info *entry_info;
04601        phar_archive_data *phar_data;
04602        zval *zobj = getThis(), arg1;
04603 
04604        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
04605               return;
04606        }
04607 
04608        entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
04609 
04610        if (entry_obj->ent.entry) {
04611               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
04612               return;
04613        }
04614 
04615        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) {
04616               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04617                      "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
04618               return;
04619        }
04620 
04621        if (phar_open_from_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
04622               efree(arch);
04623               efree(entry);
04624               if (error) {
04625                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04626                             "Cannot open phar file '%s': %s", fname, error);
04627                      efree(error);
04628               } else {
04629                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04630                             "Cannot open phar file '%s'", fname);
04631               }
04632               return;
04633        }
04634 
04635        if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error, 1 TSRMLS_CC)) == NULL) {
04636               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
04637                      "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error ? ", " : "", error ? error : "");
04638               efree(arch);
04639               efree(entry);
04640               return;
04641        }
04642 
04643        efree(arch);
04644        efree(entry);
04645 
04646        entry_obj->ent.entry = entry_info;
04647 
04648        INIT_PZVAL(&arg1);
04649        ZVAL_STRINGL(&arg1, fname, fname_len, 0);
04650 
04651        zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), 
04652               &spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1);
04653 }
04654 /* }}} */
04655 
04656 #define PHAR_ENTRY_OBJECT() \
04657        phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
04658        if (!entry_obj->ent.entry) { \
04659               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04660                      "Cannot call method on an uninitialized PharFileInfo object"); \
04661               return; \
04662        }
04663 
04664 /* {{{ proto void PharFileInfo::__destruct()
04665  * clean up directory-based entry objects
04666  */
04667 PHP_METHOD(PharFileInfo, __destruct)
04668 {
04669        phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
04670 
04671        if (entry_obj->ent.entry && entry_obj->ent.entry->is_temp_dir) {
04672               if (entry_obj->ent.entry->filename) {
04673                      efree(entry_obj->ent.entry->filename);
04674                      entry_obj->ent.entry->filename = NULL;
04675               }
04676 
04677               efree(entry_obj->ent.entry);
04678               entry_obj->ent.entry = NULL;
04679        }
04680 }
04681 /* }}} */
04682 
04683 /* {{{ proto int PharFileInfo::getCompressedSize()
04684  * Returns the compressed size
04685  */
04686 PHP_METHOD(PharFileInfo, getCompressedSize)
04687 {
04688        PHAR_ENTRY_OBJECT();
04689        
04690        if (zend_parse_parameters_none() == FAILURE) {
04691               return;
04692        }
04693 
04694        RETURN_LONG(entry_obj->ent.entry->compressed_filesize);
04695 }
04696 /* }}} */
04697 
04698 /* {{{ proto bool PharFileInfo::isCompressed([int compression_type])
04699  * Returns whether the entry is compressed, and whether it is compressed with Phar::GZ or Phar::BZ2 if specified
04700  */
04701 PHP_METHOD(PharFileInfo, isCompressed)
04702 {
04703        /* a number that is not Phar::GZ or Phar::BZ2 */
04704        long method = 9021976;
04705        PHAR_ENTRY_OBJECT();
04706 
04707        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
04708               return;
04709        }
04710 
04711        switch (method) {
04712               case 9021976:
04713                      RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK);
04714               case PHAR_ENT_COMPRESSED_GZ:
04715                      RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ);
04716               case PHAR_ENT_COMPRESSED_BZ2:
04717                      RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2);
04718               default:
04719                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04720                             "Unknown compression type specified"); \
04721        }
04722 }
04723 /* }}} */
04724 
04725 /* {{{ proto int PharFileInfo::getCRC32()
04726  * Returns CRC32 code or throws an exception if not CRC checked
04727  */
04728 PHP_METHOD(PharFileInfo, getCRC32)
04729 {
04730        PHAR_ENTRY_OBJECT();
04731        
04732        if (zend_parse_parameters_none() == FAILURE) {
04733               return;
04734        }
04735 
04736        if (entry_obj->ent.entry->is_dir) {
04737               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04738                      "Phar entry is a directory, does not have a CRC"); \
04739               return;
04740        }
04741 
04742        if (entry_obj->ent.entry->is_crc_checked) {
04743               RETURN_LONG(entry_obj->ent.entry->crc32);
04744        } else {
04745               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04746                      "Phar entry was not CRC checked"); \
04747        }
04748 }
04749 /* }}} */
04750 
04751 /* {{{ proto int PharFileInfo::isCRCChecked()
04752  * Returns whether file entry is CRC checked
04753  */
04754 PHP_METHOD(PharFileInfo, isCRCChecked)
04755 {
04756        PHAR_ENTRY_OBJECT();
04757        
04758        if (zend_parse_parameters_none() == FAILURE) {
04759               return;
04760        }
04761 
04762        RETURN_BOOL(entry_obj->ent.entry->is_crc_checked);
04763 }
04764 /* }}} */
04765 
04766 /* {{{ proto int PharFileInfo::getPharFlags()
04767  * Returns the Phar file entry flags
04768  */
04769 PHP_METHOD(PharFileInfo, getPharFlags)
04770 {
04771        PHAR_ENTRY_OBJECT();
04772        
04773        if (zend_parse_parameters_none() == FAILURE) {
04774               return;
04775        }
04776 
04777        RETURN_LONG(entry_obj->ent.entry->flags & ~(PHAR_ENT_PERM_MASK|PHAR_ENT_COMPRESSION_MASK));
04778 }
04779 /* }}} */
04780 
04781 /* {{{ proto int PharFileInfo::chmod()
04782  * set the file permissions for the Phar.  This only allows setting execution bit, read/write
04783  */
04784 PHP_METHOD(PharFileInfo, chmod)
04785 {
04786        char *error;
04787        long perms;
04788        PHAR_ENTRY_OBJECT();
04789 
04790        if (entry_obj->ent.entry->is_temp_dir) {
04791               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04792                      "Phar entry \"%s\" is a temporary directory (not an actual entry in the archive), cannot chmod", entry_obj->ent.entry->filename); \
04793               return;
04794        }
04795 
04796        if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
04797               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot modify permissions for file \"%s\" in phar \"%s\", write operations are prohibited", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
04798               return;
04799        }
04800 
04801        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perms) == FAILURE) {
04802               return;
04803        }
04804 
04805        if (entry_obj->ent.entry->is_persistent) {
04806               phar_archive_data *phar = entry_obj->ent.entry->phar;
04807 
04808               if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
04809                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
04810                      return;
04811               }
04812               /* re-populate after copy-on-write */
04813               zend_hash_find(&phar->manifest, entry_obj->ent.entry->filename, entry_obj->ent.entry->filename_len, (void **)&entry_obj->ent.entry);
04814        }
04815        /* clear permissions */
04816        entry_obj->ent.entry->flags &= ~PHAR_ENT_PERM_MASK;
04817        perms &= 0777;
04818        entry_obj->ent.entry->flags |= perms;
04819        entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
04820        entry_obj->ent.entry->phar->is_modified = 1;
04821        entry_obj->ent.entry->is_modified = 1;
04822 
04823        /* hackish cache in php_stat needs to be cleared */
04824        /* if this code fails to work, check main/streams/streams.c, _php_stream_stat_path */
04825        if (BG(CurrentLStatFile)) {
04826               efree(BG(CurrentLStatFile));
04827        }
04828 
04829        if (BG(CurrentStatFile)) {
04830               efree(BG(CurrentStatFile));
04831        }
04832 
04833        BG(CurrentLStatFile) = NULL;
04834        BG(CurrentStatFile) = NULL;
04835        phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
04836 
04837        if (error) {
04838               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
04839               efree(error);
04840        }
04841 }
04842 /* }}} */
04843 
04844 /* {{{ proto int PharFileInfo::hasMetaData()
04845  * Returns the metadata of the entry
04846  */
04847 PHP_METHOD(PharFileInfo, hasMetadata)
04848 {
04849        PHAR_ENTRY_OBJECT();
04850        
04851        if (zend_parse_parameters_none() == FAILURE) {
04852               return;
04853        }
04854 
04855        RETURN_BOOL(entry_obj->ent.entry->metadata != NULL);
04856 }
04857 /* }}} */
04858 
04859 /* {{{ proto int PharFileInfo::getMetaData()
04860  * Returns the metadata of the entry
04861  */
04862 PHP_METHOD(PharFileInfo, getMetadata)
04863 {
04864        PHAR_ENTRY_OBJECT();
04865        
04866        if (zend_parse_parameters_none() == FAILURE) {
04867               return;
04868        }
04869 
04870        if (entry_obj->ent.entry->metadata) {
04871               if (entry_obj->ent.entry->is_persistent) {
04872                      zval *ret;
04873                      char *buf = estrndup((char *) entry_obj->ent.entry->metadata, entry_obj->ent.entry->metadata_len);
04874                      /* assume success, we would have failed before */
04875                      phar_parse_metadata(&buf, &ret, entry_obj->ent.entry->metadata_len TSRMLS_CC);
04876                      efree(buf);
04877                      RETURN_ZVAL(ret, 0, 1);
04878               }
04879               RETURN_ZVAL(entry_obj->ent.entry->metadata, 1, 0);
04880        }
04881 }
04882 /* }}} */
04883 
04884 /* {{{ proto int PharFileInfo::setMetaData(mixed $metadata)
04885  * Sets the metadata of the entry
04886  */
04887 PHP_METHOD(PharFileInfo, setMetadata)
04888 {
04889        char *error;
04890        zval *metadata;
04891 
04892        PHAR_ENTRY_OBJECT();
04893 
04894        if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
04895               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
04896               return;
04897        }
04898 
04899        if (entry_obj->ent.entry->is_temp_dir) {
04900               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04901                      "Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata"); \
04902               return;
04903        }
04904 
04905        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
04906               return;
04907        }
04908 
04909        if (entry_obj->ent.entry->is_persistent) {
04910               phar_archive_data *phar = entry_obj->ent.entry->phar;
04911 
04912               if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
04913                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
04914                      return;
04915               }
04916               /* re-populate after copy-on-write */
04917               zend_hash_find(&phar->manifest, entry_obj->ent.entry->filename, entry_obj->ent.entry->filename_len, (void **)&entry_obj->ent.entry);
04918        }
04919        if (entry_obj->ent.entry->metadata) {
04920               zval_ptr_dtor(&entry_obj->ent.entry->metadata);
04921               entry_obj->ent.entry->metadata = NULL;
04922        }
04923 
04924        MAKE_STD_ZVAL(entry_obj->ent.entry->metadata);
04925        ZVAL_ZVAL(entry_obj->ent.entry->metadata, metadata, 1, 0);
04926 
04927        entry_obj->ent.entry->is_modified = 1;
04928        entry_obj->ent.entry->phar->is_modified = 1;
04929        phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
04930 
04931        if (error) {
04932               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
04933               efree(error);
04934        }
04935 }
04936 /* }}} */
04937 
04938 /* {{{ proto bool PharFileInfo::delMetaData()
04939  * Deletes the metadata of the entry
04940  */
04941 PHP_METHOD(PharFileInfo, delMetadata)
04942 {
04943        char *error;
04944 
04945        PHAR_ENTRY_OBJECT();
04946        
04947        if (zend_parse_parameters_none() == FAILURE) {
04948               return;
04949        }
04950 
04951        if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
04952               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by the php.ini setting phar.readonly");
04953               return;
04954        }
04955 
04956        if (entry_obj->ent.entry->is_temp_dir) {
04957               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
04958                      "Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata"); \
04959               return;
04960        }
04961 
04962        if (entry_obj->ent.entry->metadata) {
04963               if (entry_obj->ent.entry->is_persistent) {
04964                      phar_archive_data *phar = entry_obj->ent.entry->phar;
04965 
04966                      if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
04967                             zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
04968                             return;
04969                      }
04970                      /* re-populate after copy-on-write */
04971                      zend_hash_find(&phar->manifest, entry_obj->ent.entry->filename, entry_obj->ent.entry->filename_len, (void **)&entry_obj->ent.entry);
04972               }
04973               zval_ptr_dtor(&entry_obj->ent.entry->metadata);
04974               entry_obj->ent.entry->metadata = NULL;
04975               entry_obj->ent.entry->is_modified = 1;
04976               entry_obj->ent.entry->phar->is_modified = 1;
04977 
04978               phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
04979 
04980               if (error) {
04981                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
04982                      efree(error);
04983                      RETURN_FALSE;
04984               } else {
04985                      RETURN_TRUE;
04986               }
04987 
04988        } else {
04989               RETURN_TRUE;
04990        }
04991 }
04992 /* }}} */
04993 
04994 /* {{{ proto string PharFileInfo::getContent()
04995  * return the complete file contents of the entry (like file_get_contents)
04996  */
04997 PHP_METHOD(PharFileInfo, getContent)
04998 {
04999        char *error;
05000        php_stream *fp;
05001        phar_entry_info *link;
05002 
05003        PHAR_ENTRY_OBJECT();
05004        
05005        if (zend_parse_parameters_none() == FAILURE) {
05006               return;
05007        }
05008 
05009        if (entry_obj->ent.entry->is_dir) {
05010               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05011                      "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
05012               return;
05013        }
05014 
05015        link = phar_get_link_source(entry_obj->ent.entry TSRMLS_CC);
05016 
05017        if (!link) {
05018               link = entry_obj->ent.entry;
05019        }
05020 
05021        if (SUCCESS != phar_open_entry_fp(link, &error, 0 TSRMLS_CC)) {
05022               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05023                      "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
05024               efree(error);
05025               return;
05026        }
05027 
05028        if (!(fp = phar_get_efp(link, 0 TSRMLS_CC))) {
05029               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05030                      "Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
05031               return;
05032        }
05033 
05034        phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC);
05035        Z_TYPE_P(return_value) = IS_STRING;
05036 #if PHP_MAJOR_VERSION >= 6
05037        Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0);
05038 #else
05039        Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0);
05040 #endif
05041 
05042        if (!Z_STRVAL_P(return_value)) {
05043               Z_STRVAL_P(return_value) = estrndup("", 0);
05044        }
05045 }
05046 /* }}} */
05047 
05048 /* {{{ proto int PharFileInfo::compress(int compression_type)
05049  * Instructs the Phar class to compress the current file using zlib or bzip2 compression
05050  */
05051 PHP_METHOD(PharFileInfo, compress)
05052 {
05053        long method;
05054        char *error;
05055        PHAR_ENTRY_OBJECT();
05056 
05057        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
05058               return;
05059        }
05060 
05061        if (entry_obj->ent.entry->is_tar) {
05062               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05063                      "Cannot compress with Gzip compression, not possible with tar-based phar archives");
05064               return;
05065        }
05066 
05067        if (entry_obj->ent.entry->is_dir) {
05068               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
05069                      "Phar entry is a directory, cannot set compression"); \
05070               return;
05071        }
05072 
05073        if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
05074               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05075                      "Phar is readonly, cannot change compression");
05076               return;
05077        }
05078 
05079        if (entry_obj->ent.entry->is_deleted) {
05080               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05081                      "Cannot compress deleted file");
05082               return;
05083        }
05084 
05085        if (entry_obj->ent.entry->is_persistent) {
05086               phar_archive_data *phar = entry_obj->ent.entry->phar;
05087 
05088               if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
05089                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
05090                      return;
05091               }
05092               /* re-populate after copy-on-write */
05093               zend_hash_find(&phar->manifest, entry_obj->ent.entry->filename, entry_obj->ent.entry->filename_len, (void **)&entry_obj->ent.entry);
05094        }
05095        switch (method) {
05096               case PHAR_ENT_COMPRESSED_GZ:
05097                      if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) {
05098                             RETURN_TRUE;
05099                      }
05100 
05101                      if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0) {
05102                             if (!PHAR_G(has_bz2)) {
05103                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05104                                           "Cannot compress with gzip compression, file is already compressed with bzip2 compression and bz2 extension is not enabled, cannot decompress");
05105                                    return;
05106                             }
05107 
05108                             /* decompress this file indirectly */
05109                             if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
05110                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05111                                           "Phar error: Cannot decompress bzip2-compressed file \"%s\" in phar \"%s\" in order to compress with gzip: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
05112                                    efree(error);
05113                                    return;
05114                             }
05115                      }
05116 
05117                      if (!PHAR_G(has_zlib)) {
05118                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05119                                    "Cannot compress with gzip compression, zlib extension is not enabled");
05120                             return;
05121                      }
05122 
05123                      entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
05124                      entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
05125                      entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_GZ;
05126                      break;
05127               case PHAR_ENT_COMPRESSED_BZ2:
05128                      if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
05129                             RETURN_TRUE;
05130                      }
05131 
05132                      if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0) {
05133                             if (!PHAR_G(has_zlib)) {
05134                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05135                                           "Cannot compress with bzip2 compression, file is already compressed with gzip compression and zlib extension is not enabled, cannot decompress");
05136                                    return;
05137                             }
05138 
05139                             /* decompress this file indirectly */
05140                             if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
05141                                    zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05142                                           "Phar error: Cannot decompress gzip-compressed file \"%s\" in phar \"%s\" in order to compress with bzip2: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
05143                                    efree(error);
05144                                    return;
05145                             }
05146                      }
05147 
05148                      if (!PHAR_G(has_bz2)) {
05149                             zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05150                                    "Cannot compress with bzip2 compression, bz2 extension is not enabled");
05151                             return;
05152                      }
05153                      entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
05154                      entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
05155                      entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_BZ2;
05156                      break;
05157               default:
05158                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
05159                             "Unknown compression type specified"); \
05160        }
05161 
05162        entry_obj->ent.entry->phar->is_modified = 1;
05163        entry_obj->ent.entry->is_modified = 1;
05164        phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
05165 
05166        if (error) {
05167               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
05168               efree(error);
05169        }
05170 
05171        RETURN_TRUE;
05172 }
05173 /* }}} */
05174 
05175 /* {{{ proto int PharFileInfo::decompress()
05176  * Instructs the Phar class to decompress the current file
05177  */
05178 PHP_METHOD(PharFileInfo, decompress)
05179 {
05180        char *error;
05181        PHAR_ENTRY_OBJECT();
05182        
05183        if (zend_parse_parameters_none() == FAILURE) {
05184               return;
05185        }
05186 
05187        if (entry_obj->ent.entry->is_dir) {
05188               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
05189                      "Phar entry is a directory, cannot set compression"); \
05190               return;
05191        }
05192 
05193        if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK) == 0) {
05194               RETURN_TRUE;
05195        }
05196 
05197        if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
05198               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05199                      "Phar is readonly, cannot decompress");
05200               return;
05201        }
05202 
05203        if (entry_obj->ent.entry->is_deleted) {
05204               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05205                      "Cannot compress deleted file");
05206               return;
05207        }
05208 
05209        if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0 && !PHAR_G(has_zlib)) {
05210               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05211                      "Cannot decompress Gzip-compressed file, zlib extension is not enabled");
05212               return;
05213        }
05214 
05215        if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0 && !PHAR_G(has_bz2)) {
05216               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
05217                      "Cannot decompress Bzip2-compressed file, bz2 extension is not enabled");
05218               return;
05219        }
05220 
05221        if (entry_obj->ent.entry->is_persistent) {
05222               phar_archive_data *phar = entry_obj->ent.entry->phar;
05223 
05224               if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
05225                      zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
05226                      return;
05227               }
05228               /* re-populate after copy-on-write */
05229               zend_hash_find(&phar->manifest, entry_obj->ent.entry->filename, entry_obj->ent.entry->filename_len, (void **)&entry_obj->ent.entry);
05230        }
05231        if (!entry_obj->ent.entry->fp) {
05232               if (FAILURE == phar_open_archive_fp(entry_obj->ent.entry->phar TSRMLS_CC)) {
05233                      zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot decompress entry \"%s\", phar error: Cannot open phar archive \"%s\" for reading", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
05234                      return;
05235               }
05236               entry_obj->ent.entry->fp_type = PHAR_FP;
05237        }
05238 
05239        entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
05240        entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
05241        entry_obj->ent.entry->phar->is_modified = 1;
05242        entry_obj->ent.entry->is_modified = 1;
05243        phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
05244 
05245        if (error) {
05246               zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
05247               efree(error);
05248        }
05249        RETURN_TRUE;
05250 }
05251 /* }}} */
05252 
05253 #endif /* HAVE_SPL */
05254 
05255 /* {{{ phar methods */
05256 PHAR_ARG_INFO
05257 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar___construct, 0, 0, 1)
05258        ZEND_ARG_INFO(0, filename)
05259        ZEND_ARG_INFO(0, flags)
05260        ZEND_ARG_INFO(0, alias)
05261        ZEND_ARG_INFO(0, fileformat)
05262 ZEND_END_ARG_INFO()
05263 
05264 PHAR_ARG_INFO
05265 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_createDS, 0, 0, 0)
05266        ZEND_ARG_INFO(0, index)
05267        ZEND_ARG_INFO(0, webindex)
05268 ZEND_END_ARG_INFO()
05269 
05270 PHAR_ARG_INFO
05271 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_cancompress, 0, 0, 0)
05272        ZEND_ARG_INFO(0, method)
05273 ZEND_END_ARG_INFO()
05274 
05275 PHAR_ARG_INFO
05276 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isvalidpharfilename, 0, 0, 1)
05277        ZEND_ARG_INFO(0, filename)
05278        ZEND_ARG_INFO(0, executable)
05279 ZEND_END_ARG_INFO()
05280 
05281 PHAR_ARG_INFO
05282 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_loadPhar, 0, 0, 1)
05283        ZEND_ARG_INFO(0, filename)
05284        ZEND_ARG_INFO(0, alias)
05285 ZEND_END_ARG_INFO()
05286 
05287 PHAR_ARG_INFO
05288 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mapPhar, 0, 0, 0)
05289        ZEND_ARG_INFO(0, alias)
05290        ZEND_ARG_INFO(0, offset)
05291 ZEND_END_ARG_INFO()
05292 
05293 PHAR_ARG_INFO
05294 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mount, 0, 0, 2)
05295        ZEND_ARG_INFO(0, inphar)
05296        ZEND_ARG_INFO(0, externalfile)
05297 ZEND_END_ARG_INFO()
05298 
05299 PHAR_ARG_INFO
05300 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mungServer, 0, 0, 1)
05301        ZEND_ARG_INFO(0, munglist)
05302 ZEND_END_ARG_INFO()
05303 
05304 PHAR_ARG_INFO
05305 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_webPhar, 0, 0, 0)
05306        ZEND_ARG_INFO(0, alias)
05307        ZEND_ARG_INFO(0, index)
05308        ZEND_ARG_INFO(0, f404)
05309        ZEND_ARG_INFO(0, mimetypes)
05310        ZEND_ARG_INFO(0, rewrites)
05311 ZEND_END_ARG_INFO()
05312 
05313 PHAR_ARG_INFO
05314 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_running, 0, 0, 1)
05315        ZEND_ARG_INFO(0, retphar)
05316 ZEND_END_ARG_INFO()
05317 
05318 PHAR_ARG_INFO
05319 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_ua, 0, 0, 1)
05320        ZEND_ARG_INFO(0, archive)
05321 ZEND_END_ARG_INFO()
05322 
05323 #if HAVE_SPL
05324 PHAR_ARG_INFO
05325 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_build, 0, 0, 1)
05326        ZEND_ARG_INFO(0, iterator)
05327        ZEND_ARG_INFO(0, base_directory)
05328 ZEND_END_ARG_INFO()
05329 
05330 PHAR_ARG_INFO
05331 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_conv, 0, 0, 0)
05332        ZEND_ARG_INFO(0, format)
05333        ZEND_ARG_INFO(0, compression_type)
05334        ZEND_ARG_INFO(0, file_ext)
05335 ZEND_END_ARG_INFO()
05336 
05337 PHAR_ARG_INFO
05338 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comps, 0, 0, 1)
05339        ZEND_ARG_INFO(0, compression_type)
05340        ZEND_ARG_INFO(0, file_ext)
05341 ZEND_END_ARG_INFO()
05342 
05343 PHAR_ARG_INFO
05344 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_decomp, 0, 0, 0)
05345        ZEND_ARG_INFO(0, file_ext)
05346 ZEND_END_ARG_INFO()
05347 
05348 PHAR_ARG_INFO
05349 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comp, 0, 0, 1)
05350        ZEND_ARG_INFO(0, compression_type)
05351 ZEND_END_ARG_INFO()
05352 
05353 PHAR_ARG_INFO
05354 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_compo, 0, 0, 0)
05355        ZEND_ARG_INFO(0, compression_type)
05356 ZEND_END_ARG_INFO()
05357 
05358 PHAR_ARG_INFO
05359 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_copy, 0, 0, 2)
05360        ZEND_ARG_INFO(0, newfile)
05361        ZEND_ARG_INFO(0, oldfile)
05362 ZEND_END_ARG_INFO()
05363 
05364 PHAR_ARG_INFO
05365 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_delete, 0, 0, 1)
05366        ZEND_ARG_INFO(0, entry)
05367 ZEND_END_ARG_INFO()
05368 
05369 PHAR_ARG_INFO
05370 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromdir, 0, 0, 1)
05371        ZEND_ARG_INFO(0, base_dir)
05372        ZEND_ARG_INFO(0, regex)
05373 ZEND_END_ARG_INFO()
05374 
05375 PHAR_ARG_INFO
05376 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetExists, 0, 0, 1)
05377        ZEND_ARG_INFO(0, entry)
05378 ZEND_END_ARG_INFO()
05379 
05380 PHAR_ARG_INFO
05381 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetSet, 0, 0, 2)
05382        ZEND_ARG_INFO(0, entry)
05383        ZEND_ARG_INFO(0, value)
05384 ZEND_END_ARG_INFO()
05385 
05386 PHAR_ARG_INFO
05387 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setAlias, 0, 0, 1)
05388        ZEND_ARG_INFO(0, alias)
05389 ZEND_END_ARG_INFO()
05390 
05391 PHAR_ARG_INFO
05392 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setMetadata, 0, 0, 1)
05393        ZEND_ARG_INFO(0, metadata)
05394 ZEND_END_ARG_INFO()
05395 
05396 PHAR_ARG_INFO
05397 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setSigAlgo, 0, 0, 1)
05398        ZEND_ARG_INFO(0, algorithm)
05399        ZEND_ARG_INFO(0, privatekey)
05400 ZEND_END_ARG_INFO()
05401 
05402 PHAR_ARG_INFO
05403 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setStub, 0, 0, 1)
05404        ZEND_ARG_INFO(0, newstub)
05405        ZEND_ARG_INFO(0, maxlen)
05406 ZEND_END_ARG_INFO()
05407 
05408 PHAR_ARG_INFO
05409 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_emptydir, 0, 0, 0)
05410        ZEND_ARG_INFO(0, dirname)
05411 ZEND_END_ARG_INFO()
05412 
05413 PHAR_ARG_INFO
05414 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_extract, 0, 0, 1)
05415        ZEND_ARG_INFO(0, pathto)
05416        ZEND_ARG_INFO(0, files)
05417        ZEND_ARG_INFO(0, overwrite)
05418 ZEND_END_ARG_INFO()
05419 
05420 PHAR_ARG_INFO
05421 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_addfile, 0, 0, 1)
05422        ZEND_ARG_INFO(0, filename)
05423        ZEND_ARG_INFO(0, localname)
05424 ZEND_END_ARG_INFO()
05425 
05426 PHAR_ARG_INFO
05427 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromstring, 0, 0, 1)
05428        ZEND_ARG_INFO(0, localname)
05429        ZEND_ARG_INFO(0, contents)
05430 ZEND_END_ARG_INFO()
05431 
05432 PHAR_ARG_INFO
05433 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isff, 0, 0, 1)
05434        ZEND_ARG_INFO(0, fileformat)
05435 ZEND_END_ARG_INFO()
05436 
05437 PHAR_ARG_INFO
05438 ZEND_BEGIN_ARG_INFO(arginfo_phar__void, 0)
05439 ZEND_END_ARG_INFO()
05440 
05441 
05442 #endif /* HAVE_SPL */
05443 
05444 zend_function_entry php_archive_methods[] = {
05445 #if !HAVE_SPL
05446        PHP_ME(Phar, __construct,           arginfo_phar___construct,  ZEND_ACC_PRIVATE)
05447 #else
05448        PHP_ME(Phar, __construct,           arginfo_phar___construct,  ZEND_ACC_PUBLIC)
05449        PHP_ME(Phar, __destruct,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
05450        PHP_ME(Phar, addEmptyDir,           arginfo_phar_emptydir,     ZEND_ACC_PUBLIC)
05451        PHP_ME(Phar, addFile,               arginfo_phar_addfile,      ZEND_ACC_PUBLIC)
05452        PHP_ME(Phar, addFromString,         arginfo_phar_fromstring,   ZEND_ACC_PUBLIC)
05453        PHP_ME(Phar, buildFromDirectory,    arginfo_phar_fromdir,      ZEND_ACC_PUBLIC)
05454        PHP_ME(Phar, buildFromIterator,     arginfo_phar_build,        ZEND_ACC_PUBLIC)
05455        PHP_ME(Phar, compressFiles,         arginfo_phar_comp,         ZEND_ACC_PUBLIC)
05456        PHP_ME(Phar, decompressFiles,       arginfo_phar__void,        ZEND_ACC_PUBLIC)
05457        PHP_ME(Phar, compress,              arginfo_phar_comps,        ZEND_ACC_PUBLIC)
05458        PHP_ME(Phar, decompress,            arginfo_phar_decomp,       ZEND_ACC_PUBLIC)
05459        PHP_ME(Phar, convertToExecutable,   arginfo_phar_conv,         ZEND_ACC_PUBLIC)
05460        PHP_ME(Phar, convertToData,         arginfo_phar_conv,         ZEND_ACC_PUBLIC)
05461        PHP_ME(Phar, copy,                  arginfo_phar_copy,         ZEND_ACC_PUBLIC)
05462        PHP_ME(Phar, count,                 arginfo_phar__void,        ZEND_ACC_PUBLIC)
05463        PHP_ME(Phar, delete,                arginfo_phar_delete,       ZEND_ACC_PUBLIC)
05464        PHP_ME(Phar, delMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
05465        PHP_ME(Phar, extractTo,             arginfo_phar_extract,      ZEND_ACC_PUBLIC)
05466        PHP_ME(Phar, getAlias,              arginfo_phar__void,        ZEND_ACC_PUBLIC)
05467        PHP_ME(Phar, getPath,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
05468        PHP_ME(Phar, getMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
05469        PHP_ME(Phar, getModified,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
05470        PHP_ME(Phar, getSignature,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
05471        PHP_ME(Phar, getStub,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
05472        PHP_ME(Phar, getVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
05473        PHP_ME(Phar, hasMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
05474        PHP_ME(Phar, isBuffering,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
05475        PHP_ME(Phar, isCompressed,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
05476        PHP_ME(Phar, isFileFormat,          arginfo_phar_isff,         ZEND_ACC_PUBLIC)
05477        PHP_ME(Phar, isWritable,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
05478        PHP_ME(Phar, offsetExists,          arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
05479        PHP_ME(Phar, offsetGet,             arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
05480        PHP_ME(Phar, offsetSet,             arginfo_phar_offsetSet,    ZEND_ACC_PUBLIC)
05481        PHP_ME(Phar, offsetUnset,           arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
05482        PHP_ME(Phar, setAlias,              arginfo_phar_setAlias,     ZEND_ACC_PUBLIC)
05483        PHP_ME(Phar, setDefaultStub,        arginfo_phar_createDS,     ZEND_ACC_PUBLIC)
05484        PHP_ME(Phar, setMetadata,           arginfo_phar_setMetadata,  ZEND_ACC_PUBLIC)
05485        PHP_ME(Phar, setSignatureAlgorithm, arginfo_phar_setSigAlgo,   ZEND_ACC_PUBLIC)
05486        PHP_ME(Phar, setStub,               arginfo_phar_setStub,      ZEND_ACC_PUBLIC)
05487        PHP_ME(Phar, startBuffering,        arginfo_phar__void,        ZEND_ACC_PUBLIC)
05488        PHP_ME(Phar, stopBuffering,         arginfo_phar__void,        ZEND_ACC_PUBLIC)
05489 #endif
05490        /* static member functions */
05491        PHP_ME(Phar, apiVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05492        PHP_ME(Phar, canCompress,           arginfo_phar_cancompress,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05493        PHP_ME(Phar, canWrite,              arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05494        PHP_ME(Phar, createDefaultStub,     arginfo_phar_createDS,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05495        PHP_ME(Phar, getSupportedCompression,arginfo_phar__void,       ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05496        PHP_ME(Phar, getSupportedSignatures,arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05497        PHP_ME(Phar, interceptFileFuncs,    arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05498        PHP_ME(Phar, isValidPharFilename,   arginfo_phar_isvalidpharfilename, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05499        PHP_ME(Phar, loadPhar,              arginfo_phar_loadPhar,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05500        PHP_ME(Phar, mapPhar,               arginfo_phar_mapPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05501        PHP_ME(Phar, running,               arginfo_phar_running,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05502        PHP_ME(Phar, mount,                 arginfo_phar_mount,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05503        PHP_ME(Phar, mungServer,            arginfo_phar_mungServer,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05504        PHP_ME(Phar, unlinkArchive,         arginfo_phar_ua,           ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05505        PHP_ME(Phar, webPhar,               arginfo_phar_webPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
05506        PHP_FE_END
05507 };
05508 
05509 #if HAVE_SPL
05510 PHAR_ARG_INFO
05511 ZEND_BEGIN_ARG_INFO_EX(arginfo_entry___construct, 0, 0, 1)
05512        ZEND_ARG_INFO(0, filename)
05513 ZEND_END_ARG_INFO()
05514 
05515 PHAR_ARG_INFO
05516 ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_chmod, 0, 0, 1)
05517        ZEND_ARG_INFO(0, perms)
05518 ZEND_END_ARG_INFO()
05519 
05520 zend_function_entry php_entry_methods[] = {
05521        PHP_ME(PharFileInfo, __construct,        arginfo_entry___construct,  ZEND_ACC_PUBLIC)
05522        PHP_ME(PharFileInfo, __destruct,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
05523        PHP_ME(PharFileInfo, chmod,              arginfo_entry_chmod,        ZEND_ACC_PUBLIC)
05524        PHP_ME(PharFileInfo, compress,           arginfo_phar_comp,          ZEND_ACC_PUBLIC)
05525        PHP_ME(PharFileInfo, decompress,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
05526        PHP_ME(PharFileInfo, delMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
05527        PHP_ME(PharFileInfo, getCompressedSize,  arginfo_phar__void,         ZEND_ACC_PUBLIC)
05528        PHP_ME(PharFileInfo, getCRC32,           arginfo_phar__void,         ZEND_ACC_PUBLIC)
05529        PHP_ME(PharFileInfo, getContent,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
05530        PHP_ME(PharFileInfo, getMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
05531        PHP_ME(PharFileInfo, getPharFlags,       arginfo_phar__void,         ZEND_ACC_PUBLIC)
05532        PHP_ME(PharFileInfo, hasMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
05533        PHP_ME(PharFileInfo, isCompressed,       arginfo_phar_compo,         ZEND_ACC_PUBLIC)
05534        PHP_ME(PharFileInfo, isCRCChecked,       arginfo_phar__void,         ZEND_ACC_PUBLIC)
05535        PHP_ME(PharFileInfo, setMetadata,        arginfo_phar_setMetadata,   ZEND_ACC_PUBLIC)
05536        PHP_FE_END
05537 };
05538 #endif /* HAVE_SPL */
05539 
05540 zend_function_entry phar_exception_methods[] = {
05541        PHP_FE_END
05542 };
05543 /* }}} */
05544 
05545 #define REGISTER_PHAR_CLASS_CONST_LONG(class_name, const_name, value) \
05546        zend_declare_class_constant_long(class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
05547 
05548 #if PHP_VERSION_ID < 50200
05549 # define phar_exception_get_default() zend_exception_get_default()
05550 #else
05551 # define phar_exception_get_default() zend_exception_get_default(TSRMLS_C)
05552 #endif
05553 
05554 void phar_object_init(TSRMLS_D) /* {{{ */
05555 {
05556        zend_class_entry ce;
05557 
05558        INIT_CLASS_ENTRY(ce, "PharException", phar_exception_methods);
05559        phar_ce_PharException = zend_register_internal_class_ex(&ce, phar_exception_get_default(), NULL  TSRMLS_CC);
05560 
05561 #if HAVE_SPL
05562        INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
05563        phar_ce_archive = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL  TSRMLS_CC);
05564 
05565        zend_class_implements(phar_ce_archive TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
05566 
05567        INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
05568        phar_ce_data = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL  TSRMLS_CC);
05569 
05570        zend_class_implements(phar_ce_data TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
05571 
05572        INIT_CLASS_ENTRY(ce, "PharFileInfo", php_entry_methods);
05573        phar_ce_entry = zend_register_internal_class_ex(&ce, spl_ce_SplFileInfo, NULL  TSRMLS_CC);
05574 #else
05575        INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
05576        phar_ce_archive = zend_register_internal_class(&ce TSRMLS_CC);
05577        phar_ce_archive->ce_flags |= ZEND_ACC_FINAL_CLASS;
05578 
05579        INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
05580        phar_ce_data = zend_register_internal_class(&ce TSRMLS_CC);
05581        phar_ce_data->ce_flags |= ZEND_ACC_FINAL_CLASS;
05582 #endif
05583 
05584        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "BZ2", PHAR_ENT_COMPRESSED_BZ2)
05585        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "GZ", PHAR_ENT_COMPRESSED_GZ)
05586        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "NONE", PHAR_ENT_COMPRESSED_NONE)
05587        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHAR", PHAR_FORMAT_PHAR)
05588        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "TAR", PHAR_FORMAT_TAR)
05589        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "ZIP", PHAR_FORMAT_ZIP)
05590        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "COMPRESSED", PHAR_ENT_COMPRESSION_MASK)
05591        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHP", PHAR_MIME_PHP)
05592        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHPS", PHAR_MIME_PHPS)
05593        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "MD5", PHAR_SIG_MD5)
05594        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "OPENSSL", PHAR_SIG_OPENSSL)
05595        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA1", PHAR_SIG_SHA1)
05596        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA256", PHAR_SIG_SHA256)
05597        REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA512", PHAR_SIG_SHA512)
05598 }
05599 /* }}} */
05600 
05601 /*
05602  * Local variables:
05603  * tab-width: 4
05604  * c-basic-offset: 4
05605  * End:
05606  * vim600: noet sw=4 ts=4 fdm=marker
05607  * vim<600: noet sw=4 ts=4
05608  */