Annotation of embedaddon/php/ext/phar/phar_object.c, revision 1.1.1.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>