Annotation of embedaddon/php/ext/phar/phar.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | phar php single-file executable PHP extension                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 2005-2012 The PHP Group                                |
        !             6:   +----------------------------------------------------------------------+
        !             7:   | This source file is subject to version 3.01 of the PHP license,      |
        !             8:   | that is bundled with this package in the file LICENSE, and is        |
        !             9:   | available through the world-wide-web at the following url:           |
        !            10:   | http://www.php.net/license/3_01.txt.                                 |
        !            11:   | If you did not receive a copy of the PHP license and are unable to   |
        !            12:   | obtain it through the world-wide-web, please send a note to          |
        !            13:   | license@php.net so we can mail you a copy immediately.               |
        !            14:   +----------------------------------------------------------------------+
        !            15:   | Authors: Gregory Beaver <cellog@php.net>                             |
        !            16:   |          Marcus Boerger <helly@php.net>                              |
        !            17:   +----------------------------------------------------------------------+
        !            18: */
        !            19: 
        !            20: /* $Id: phar.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            21: 
        !            22: #define PHAR_MAIN 1
        !            23: #include "phar_internal.h"
        !            24: #include "SAPI.h"
        !            25: #include "func_interceptors.h"
        !            26: 
        !            27: static void destroy_phar_data(void *pDest);
        !            28: 
        !            29: ZEND_DECLARE_MODULE_GLOBALS(phar)
        !            30: #if PHP_VERSION_ID >= 50300
        !            31: char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
        !            32: #endif
        !            33: 
        !            34: /**
        !            35:  * set's phar->is_writeable based on the current INI value
        !            36:  */
        !            37: static int phar_set_writeable_bit(void *pDest, void *argument TSRMLS_DC) /* {{{ */
        !            38: {
        !            39:        zend_bool keep = *(zend_bool *)argument;
        !            40:        phar_archive_data *phar = *(phar_archive_data **)pDest;
        !            41: 
        !            42:        if (!phar->is_data) {
        !            43:                phar->is_writeable = !keep;
        !            44:        }
        !            45: 
        !            46:        return ZEND_HASH_APPLY_KEEP;
        !            47: }
        !            48: /* }}} */
        !            49: 
        !            50: /* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
        !            51: ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
        !            52: {
        !            53:        zend_bool old, ini;
        !            54: 
        !            55:        if (entry->name_length == 14) {
        !            56:                old = PHAR_G(readonly_orig);
        !            57:        } else {
        !            58:                old = PHAR_G(require_hash_orig);
        !            59:        }
        !            60: 
        !            61:        if (new_value_length == 2 && !strcasecmp("on", new_value)) {
        !            62:                ini = (zend_bool) 1;
        !            63:        }
        !            64:        else if (new_value_length == 3 && !strcasecmp("yes", new_value)) {
        !            65:                ini = (zend_bool) 1;
        !            66:        }
        !            67:        else if (new_value_length == 4 && !strcasecmp("true", new_value)) {
        !            68:                ini = (zend_bool) 1;
        !            69:        }
        !            70:        else {
        !            71:                ini = (zend_bool) atoi(new_value);
        !            72:        }
        !            73: 
        !            74:        /* do not allow unsetting in runtime */
        !            75:        if (stage == ZEND_INI_STAGE_STARTUP) {
        !            76:                if (entry->name_length == 14) {
        !            77:                        PHAR_G(readonly_orig) = ini;
        !            78:                } else {
        !            79:                        PHAR_G(require_hash_orig) = ini;
        !            80:                }
        !            81:        } else if (old && !ini) {
        !            82:                return FAILURE;
        !            83:        }
        !            84: 
        !            85:        if (entry->name_length == 14) {
        !            86:                PHAR_G(readonly) = ini;
        !            87:                if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets) {
        !            88:                        zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC);
        !            89:                }
        !            90:        } else {
        !            91:                PHAR_G(require_hash) = ini;
        !            92:        }
        !            93: 
        !            94:        return SUCCESS;
        !            95: }
        !            96: /* }}}*/
        !            97: 
        !            98: /* this global stores the global cached pre-parsed manifests */
        !            99: HashTable cached_phars;
        !           100: HashTable cached_alias;
        !           101: 
        !           102: static void phar_split_cache_list(TSRMLS_D) /* {{{ */
        !           103: {
        !           104:        char *tmp;
        !           105:        char *key, *lasts, *end;
        !           106:        char ds[2];
        !           107:        phar_archive_data *phar;
        !           108:        uint i = 0;
        !           109: 
        !           110:        if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) {
        !           111:                return;
        !           112:        }
        !           113: 
        !           114:        ds[0] = DEFAULT_DIR_SEPARATOR;
        !           115:        ds[1] = '\0';
        !           116:        tmp = estrdup(PHAR_GLOBALS->cache_list);
        !           117: 
        !           118:        /* fake request startup */
        !           119:        PHAR_GLOBALS->request_init = 1;
        !           120:        if (zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0) == SUCCESS) {
        !           121:                EG(regular_list).nNextFreeElement=1;    /* we don't want resource id 0 */
        !           122:        }
        !           123: 
        !           124:        PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
        !           125:        PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
        !           126:        /* these two are dummies and will be destroyed later */
        !           127:        zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
        !           128:        zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
        !           129:        /* these two are real and will be copied over cached_phars/cached_alias later */
        !           130:        zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
        !           131:        zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
        !           132:        PHAR_GLOBALS->manifest_cached = 1;
        !           133:        PHAR_GLOBALS->persist = 1;
        !           134: 
        !           135:        for (key = php_strtok_r(tmp, ds, &lasts);
        !           136:                        key;
        !           137:                        key = php_strtok_r(NULL, ds, &lasts)) {
        !           138:                end = strchr(key, DEFAULT_DIR_SEPARATOR);
        !           139: 
        !           140:                if (end) {
        !           141:                        if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
        !           142: finish_up:
        !           143:                                phar->phar_pos = i++;
        !           144:                                php_stream_close(phar->fp);
        !           145:                                phar->fp = NULL;
        !           146:                        } else {
        !           147: finish_error:
        !           148:                                PHAR_GLOBALS->persist = 0;
        !           149:                                PHAR_GLOBALS->manifest_cached = 0;
        !           150:                                efree(tmp);
        !           151:                                zend_hash_destroy(&(PHAR_G(phar_fname_map)));
        !           152:                                PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
        !           153:                                zend_hash_destroy(&(PHAR_G(phar_alias_map)));
        !           154:                                PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
        !           155:                                zend_hash_destroy(&cached_phars);
        !           156:                                zend_hash_destroy(&cached_alias);
        !           157:                                zend_hash_graceful_reverse_destroy(&EG(regular_list));
        !           158:                                memset(&EG(regular_list), 0, sizeof(HashTable));
        !           159:                                /* free cached manifests */
        !           160:                                PHAR_GLOBALS->request_init = 0;
        !           161:                                return;
        !           162:                        }
        !           163:                } else {
        !           164:                        if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
        !           165:                                goto finish_up;
        !           166:                        } else {
        !           167:                                goto finish_error;
        !           168:                        }
        !           169:                }
        !           170:        }
        !           171: 
        !           172:        PHAR_GLOBALS->persist = 0;
        !           173:        PHAR_GLOBALS->request_init = 0;
        !           174:        /* destroy dummy values from before */
        !           175:        zend_hash_destroy(&cached_phars);
        !           176:        zend_hash_destroy(&cached_alias);
        !           177:        cached_phars = PHAR_GLOBALS->phar_fname_map;
        !           178:        cached_alias = PHAR_GLOBALS->phar_alias_map;
        !           179:        PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
        !           180:        PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
        !           181:        zend_hash_graceful_reverse_destroy(&EG(regular_list));
        !           182:        memset(&EG(regular_list), 0, sizeof(HashTable));
        !           183:        efree(tmp);
        !           184: }
        !           185: /* }}} */
        !           186: 
        !           187: ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
        !           188: {
        !           189:        PHAR_G(cache_list) = new_value;
        !           190: 
        !           191:        if (stage == ZEND_INI_STAGE_STARTUP) {
        !           192:                phar_split_cache_list(TSRMLS_C);
        !           193:        }
        !           194: 
        !           195:        return SUCCESS;
        !           196: }
        !           197: /* }}} */
        !           198: 
        !           199: PHP_INI_BEGIN()
        !           200:        STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
        !           201:        STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
        !           202:        STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
        !           203: PHP_INI_END()
        !           204: 
        !           205: /**
        !           206:  * When all uses of a phar have been concluded, this frees the manifest
        !           207:  * and the phar slot
        !           208:  */
        !           209: void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
        !           210: {
        !           211:        if (phar->alias && phar->alias != phar->fname) {
        !           212:                pefree(phar->alias, phar->is_persistent);
        !           213:                phar->alias = NULL;
        !           214:        }
        !           215: 
        !           216:        if (phar->fname) {
        !           217:                pefree(phar->fname, phar->is_persistent);
        !           218:                phar->fname = NULL;
        !           219:        }
        !           220: 
        !           221:        if (phar->signature) {
        !           222:                pefree(phar->signature, phar->is_persistent);
        !           223:                phar->signature = NULL;
        !           224:        }
        !           225: 
        !           226:        if (phar->manifest.arBuckets) {
        !           227:                zend_hash_destroy(&phar->manifest);
        !           228:                phar->manifest.arBuckets = NULL;
        !           229:        }
        !           230: 
        !           231:        if (phar->mounted_dirs.arBuckets) {
        !           232:                zend_hash_destroy(&phar->mounted_dirs);
        !           233:                phar->mounted_dirs.arBuckets = NULL;
        !           234:        }
        !           235: 
        !           236:        if (phar->virtual_dirs.arBuckets) {
        !           237:                zend_hash_destroy(&phar->virtual_dirs);
        !           238:                phar->virtual_dirs.arBuckets = NULL;
        !           239:        }
        !           240: 
        !           241:        if (phar->metadata) {
        !           242:                if (phar->is_persistent) {
        !           243:                        if (phar->metadata_len) {
        !           244:                                /* for zip comments that are strings */
        !           245:                                free(phar->metadata);
        !           246:                        } else {
        !           247:                                zval_internal_ptr_dtor(&phar->metadata);
        !           248:                        }
        !           249:                } else {
        !           250:                        zval_ptr_dtor(&phar->metadata);
        !           251:                }
        !           252:                phar->metadata_len = 0;
        !           253:                phar->metadata = 0;
        !           254:        }
        !           255: 
        !           256:        if (phar->fp) {
        !           257:                php_stream_close(phar->fp);
        !           258:                phar->fp = 0;
        !           259:        }
        !           260: 
        !           261:        if (phar->ufp) {
        !           262:                php_stream_close(phar->ufp);
        !           263:                phar->ufp = 0;
        !           264:        }
        !           265: 
        !           266:        pefree(phar, phar->is_persistent);
        !           267: }
        !           268: /* }}}*/
        !           269: 
        !           270: /**
        !           271:  * Delete refcount and destruct if needed. On destruct return 1 else 0.
        !           272:  */
        !           273: int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
        !           274: {
        !           275:        if (phar->is_persistent) {
        !           276:                return 0;
        !           277:        }
        !           278: 
        !           279:        if (--phar->refcount < 0) {
        !           280:                if (PHAR_GLOBALS->request_done
        !           281:                || zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
        !           282:                        phar_destroy_phar_data(phar TSRMLS_CC);
        !           283:                }
        !           284:                return 1;
        !           285:        } else if (!phar->refcount) {
        !           286:                /* invalidate phar cache */
        !           287:                PHAR_G(last_phar) = NULL;
        !           288:                PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
        !           289: 
        !           290:                if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
        !           291:                        /* close open file handle - allows removal or rename of
        !           292:                        the file on windows, which has greedy locking
        !           293:                        only close if the archive was not already compressed.  If it
        !           294:                        was compressed, then the fp does not refer to the original file */
        !           295:                        php_stream_close(phar->fp);
        !           296:                        phar->fp = NULL;
        !           297:                }
        !           298: 
        !           299:                if (!zend_hash_num_elements(&phar->manifest)) {
        !           300:                        /* this is a new phar that has perhaps had an alias/metadata set, but has never
        !           301:                        been flushed */
        !           302:                        if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
        !           303:                                phar_destroy_phar_data(phar TSRMLS_CC);
        !           304:                        }
        !           305:                        return 1;
        !           306:                }
        !           307:        }
        !           308:        return 0;
        !           309: }
        !           310: /* }}}*/
        !           311: 
        !           312: /**
        !           313:  * Destroy phar's in shutdown, here we don't care about aliases
        !           314:  */
        !           315: static void destroy_phar_data_only(void *pDest) /* {{{ */
        !           316: {
        !           317:        phar_archive_data *phar_data = *(phar_archive_data **) pDest;
        !           318:        TSRMLS_FETCH();
        !           319: 
        !           320:        if (EG(exception) || --phar_data->refcount < 0) {
        !           321:                phar_destroy_phar_data(phar_data TSRMLS_CC);
        !           322:        }
        !           323: }
        !           324: /* }}}*/
        !           325: 
        !           326: /**
        !           327:  * Delete aliases to phar's that got kicked out of the global table
        !           328:  */
        !           329: static int phar_unalias_apply(void *pDest, void *argument TSRMLS_DC) /* {{{ */
        !           330: {
        !           331:        return *(void**)pDest == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
        !           332: }
        !           333: /* }}} */
        !           334: 
        !           335: /**
        !           336:  * Delete aliases to phar's that got kicked out of the global table
        !           337:  */
        !           338: static int phar_tmpclose_apply(void *pDest TSRMLS_DC) /* {{{ */
        !           339: {
        !           340:        phar_entry_info *entry = (phar_entry_info *) pDest;
        !           341: 
        !           342:        if (entry->fp_type != PHAR_TMP) {
        !           343:                return ZEND_HASH_APPLY_KEEP;
        !           344:        }
        !           345: 
        !           346:        if (entry->fp && !entry->fp_refcount) {
        !           347:                php_stream_close(entry->fp);
        !           348:                entry->fp = NULL;
        !           349:        }
        !           350: 
        !           351:        return ZEND_HASH_APPLY_KEEP;
        !           352: }
        !           353: /* }}} */
        !           354: 
        !           355: /**
        !           356:  * Filename map destructor
        !           357:  */
        !           358: static void destroy_phar_data(void *pDest) /* {{{ */
        !           359: {
        !           360:        phar_archive_data *phar_data = *(phar_archive_data **) pDest;
        !           361:        TSRMLS_FETCH();
        !           362: 
        !           363:        if (PHAR_GLOBALS->request_ends) {
        !           364:                /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
        !           365:                this prevents unnecessary unfreed stream resources */
        !           366:                zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC);
        !           367:                destroy_phar_data_only(pDest);
        !           368:                return;
        !           369:        }
        !           370: 
        !           371:        zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
        !           372: 
        !           373:        if (--phar_data->refcount < 0) {
        !           374:                phar_destroy_phar_data(phar_data TSRMLS_CC);
        !           375:        }
        !           376: }
        !           377: /* }}}*/
        !           378: 
        !           379: /**
        !           380:  * destructor for the manifest hash, frees each file's entry
        !           381:  */
        !           382: void destroy_phar_manifest_entry(void *pDest) /* {{{ */
        !           383: {
        !           384:        phar_entry_info *entry = (phar_entry_info *)pDest;
        !           385:        TSRMLS_FETCH();
        !           386: 
        !           387:        if (entry->cfp) {
        !           388:                php_stream_close(entry->cfp);
        !           389:                entry->cfp = 0;
        !           390:        }
        !           391: 
        !           392:        if (entry->fp) {
        !           393:                php_stream_close(entry->fp);
        !           394:                entry->fp = 0;
        !           395:        }
        !           396: 
        !           397:        if (entry->metadata) {
        !           398:                if (entry->is_persistent) {
        !           399:                        if (entry->metadata_len) {
        !           400:                                /* for zip comments that are strings */
        !           401:                                free(entry->metadata);
        !           402:                        } else {
        !           403:                                zval_internal_ptr_dtor(&entry->metadata);
        !           404:                        }
        !           405:                } else {
        !           406:                        zval_ptr_dtor(&entry->metadata);
        !           407:                }
        !           408:                entry->metadata_len = 0;
        !           409:                entry->metadata = 0;
        !           410:        }
        !           411: 
        !           412:        if (entry->metadata_str.c) {
        !           413:                smart_str_free(&entry->metadata_str);
        !           414:                entry->metadata_str.c = 0;
        !           415:        }
        !           416: 
        !           417:        pefree(entry->filename, entry->is_persistent);
        !           418: 
        !           419:        if (entry->link) {
        !           420:                pefree(entry->link, entry->is_persistent);
        !           421:                entry->link = 0;
        !           422:        }
        !           423: 
        !           424:        if (entry->tmp) {
        !           425:                pefree(entry->tmp, entry->is_persistent);
        !           426:                entry->tmp = 0;
        !           427:        }
        !           428: }
        !           429: /* }}} */
        !           430: 
        !           431: int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */
        !           432: {
        !           433:        int ret = 0;
        !           434: 
        !           435:        if (idata->internal_file && !idata->internal_file->is_persistent) {
        !           436:                if (--idata->internal_file->fp_refcount < 0) {
        !           437:                        idata->internal_file->fp_refcount = 0;
        !           438:                }
        !           439: 
        !           440:                if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
        !           441:                        php_stream_close(idata->fp);
        !           442:                }
        !           443:                /* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
        !           444:                if (idata->internal_file->is_temp_dir) {
        !           445:                        destroy_phar_manifest_entry((void *)idata->internal_file);
        !           446:                        efree(idata->internal_file);
        !           447:                }
        !           448:        }
        !           449: 
        !           450:        phar_archive_delref(idata->phar TSRMLS_CC);
        !           451:        efree(idata);
        !           452:        return ret;
        !           453: }
        !           454: /* }}} */
        !           455: 
        !           456: /**
        !           457:  * Removes an entry, either by actually removing it or by marking it.
        !           458:  */
        !           459: void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */
        !           460: {
        !           461:        phar_archive_data *phar;
        !           462: 
        !           463:        phar = idata->phar;
        !           464: 
        !           465:        if (idata->internal_file->fp_refcount < 2) {
        !           466:                if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
        !           467:                        php_stream_close(idata->fp);
        !           468:                }
        !           469:                zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
        !           470:                idata->phar->refcount--;
        !           471:                efree(idata);
        !           472:        } else {
        !           473:                idata->internal_file->is_deleted = 1;
        !           474:                phar_entry_delref(idata TSRMLS_CC);
        !           475:        }
        !           476: 
        !           477:        if (!phar->donotflush) {
        !           478:                phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
        !           479:        }
        !           480: }
        !           481: /* }}} */
        !           482: 
        !           483: #define MAPPHAR_ALLOC_FAIL(msg) \
        !           484:        if (fp) {\
        !           485:                php_stream_close(fp);\
        !           486:        }\
        !           487:        if (error) {\
        !           488:                spprintf(error, 0, msg, fname);\
        !           489:        }\
        !           490:        return FAILURE;
        !           491: 
        !           492: #define MAPPHAR_FAIL(msg) \
        !           493:        efree(savebuf);\
        !           494:        if (mydata) {\
        !           495:                phar_destroy_phar_data(mydata TSRMLS_CC);\
        !           496:        }\
        !           497:        if (signature) {\
        !           498:                pefree(signature, PHAR_G(persist));\
        !           499:        }\
        !           500:        MAPPHAR_ALLOC_FAIL(msg)
        !           501: 
        !           502: #ifdef WORDS_BIGENDIAN
        !           503: # define PHAR_GET_32(buffer, var) \
        !           504:        var = ((((unsigned char*)(buffer))[3]) << 24) \
        !           505:                | ((((unsigned char*)(buffer))[2]) << 16) \
        !           506:                | ((((unsigned char*)(buffer))[1]) <<  8) \
        !           507:                | (((unsigned char*)(buffer))[0]); \
        !           508:        (buffer) += 4
        !           509: # define PHAR_GET_16(buffer, var) \
        !           510:        var = ((((unsigned char*)(buffer))[1]) <<  8) \
        !           511:                | (((unsigned char*)(buffer))[0]); \
        !           512:        (buffer) += 2
        !           513: #else
        !           514: # define PHAR_GET_32(buffer, var) \
        !           515:        memcpy(&var, buffer, sizeof(var)); \
        !           516:        buffer += 4
        !           517: # define PHAR_GET_16(buffer, var) \
        !           518:        var = *(php_uint16*)(buffer); \
        !           519:        buffer += 2
        !           520: #endif
        !           521: #define PHAR_ZIP_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
        !           522:        (((php_uint16)var[1]) & 0xff) << 8))
        !           523: #define PHAR_ZIP_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
        !           524:        (((php_uint32)var[1]) & 0xff) << 8 | \
        !           525:        (((php_uint32)var[2]) & 0xff) << 16 | \
        !           526:        (((php_uint32)var[3]) & 0xff) << 24))
        !           527: 
        !           528: /**
        !           529:  * Open an already loaded phar
        !           530:  */
        !           531: int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
        !           532: {
        !           533:        phar_archive_data *phar;
        !           534: #ifdef PHP_WIN32
        !           535:        char *unixfname;
        !           536: #endif
        !           537: 
        !           538:        if (error) {
        !           539:                *error = NULL;
        !           540:        }
        !           541: #ifdef PHP_WIN32
        !           542:        unixfname = estrndup(fname, fname_len);
        !           543:        phar_unixify_path_separators(unixfname, fname_len);
        !           544: 
        !           545:        if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
        !           546:                && ((alias && fname_len == phar->fname_len
        !           547:                && !strncmp(unixfname, phar->fname, fname_len)) || !alias)
        !           548:        ) {
        !           549:                phar_entry_info *stub;
        !           550:                efree(unixfname);
        !           551: #else
        !           552:        if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC)
        !           553:                && ((alias && fname_len == phar->fname_len
        !           554:                && !strncmp(fname, phar->fname, fname_len)) || !alias)
        !           555:        ) {
        !           556:                phar_entry_info *stub;
        !           557: #endif
        !           558:                /* logic above is as follows:
        !           559:                   If an explicit alias was requested, ensure the filename passed in
        !           560:                   matches the phar's filename.
        !           561:                   If no alias was passed in, then it can match either and be valid
        !           562:                 */
        !           563: 
        !           564:                if (!is_data) {
        !           565:                        /* prevent any ".phar" without a stub getting through */
        !           566:                        if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
        !           567:                                if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
        !           568:                                        if (error) {
        !           569:                                                spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
        !           570:                                        }
        !           571:                                        return FAILURE;
        !           572:                                }
        !           573:                        }
        !           574:                }
        !           575: 
        !           576:                if (pphar) {
        !           577:                        *pphar = phar;
        !           578:                }
        !           579: 
        !           580:                return SUCCESS;
        !           581:        } else {
        !           582: #ifdef PHP_WIN32
        !           583:                efree(unixfname);
        !           584: #endif
        !           585:                if (pphar) {
        !           586:                        *pphar = NULL;
        !           587:                }
        !           588: 
        !           589:                if (phar && error && !(options & REPORT_ERRORS)) {
        !           590:                        efree(error);
        !           591:                }
        !           592: 
        !           593:                return FAILURE;
        !           594:        }
        !           595: }
        !           596: /* }}}*/
        !           597: 
        !           598: /**
        !           599:  * Parse out metadata from the manifest for a single file
        !           600:  *
        !           601:  * Meta-data is in this format:
        !           602:  * [len32][data...]
        !           603:  * 
        !           604:  * data is the serialized zval
        !           605:  */
        !           606: int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */
        !           607: {
        !           608:        const unsigned char *p;
        !           609:        php_uint32 buf_len;
        !           610:        php_unserialize_data_t var_hash;
        !           611: 
        !           612:        if (!zip_metadata_len) {
        !           613:                PHAR_GET_32(*buffer, buf_len);
        !           614:        } else {
        !           615:                buf_len = zip_metadata_len;
        !           616:        }
        !           617: 
        !           618:        if (buf_len) {
        !           619:                ALLOC_ZVAL(*metadata);
        !           620:                INIT_ZVAL(**metadata);
        !           621:                p = (const unsigned char*) *buffer;
        !           622:                PHP_VAR_UNSERIALIZE_INIT(var_hash);
        !           623: 
        !           624:                if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
        !           625:                        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
        !           626:                        zval_ptr_dtor(metadata);
        !           627:                        *metadata = NULL;
        !           628:                        return FAILURE;
        !           629:                }
        !           630: 
        !           631:                PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
        !           632: 
        !           633:                if (PHAR_G(persist)) {
        !           634:                        /* lazy init metadata */
        !           635:                        zval_ptr_dtor(metadata);
        !           636:                        *metadata = (zval *) pemalloc(buf_len, 1);
        !           637:                        memcpy(*metadata, *buffer, buf_len);
        !           638:                        *buffer += buf_len;
        !           639:                        return SUCCESS;
        !           640:                }
        !           641:        } else {
        !           642:                *metadata = NULL;
        !           643:        }
        !           644: 
        !           645:        if (!zip_metadata_len) {
        !           646:                *buffer += buf_len;
        !           647:        }
        !           648: 
        !           649:        return SUCCESS;
        !           650: }
        !           651: /* }}}*/
        !           652: 
        !           653: /**
        !           654:  * Does not check for a previously opened phar in the cache.
        !           655:  *
        !           656:  * Parse a new one and add it to the cache, returning either SUCCESS or
        !           657:  * FAILURE, and setting pphar to the pointer to the manifest entry
        !           658:  * 
        !           659:  * This is used by phar_open_from_filename to process the manifest, but can be called
        !           660:  * directly.
        !           661:  */
        !           662: static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
        !           663: {
        !           664:        char b32[4], *buffer, *endbuffer, *savebuf;
        !           665:        phar_archive_data *mydata = NULL;
        !           666:        phar_entry_info entry;
        !           667:        php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
        !           668:        php_uint16 manifest_ver;
        !           669:        long offset;
        !           670:        int sig_len, register_alias = 0, temp_alias = 0;
        !           671:        char *signature = NULL;
        !           672: 
        !           673:        if (pphar) {
        !           674:                *pphar = NULL;
        !           675:        }
        !           676: 
        !           677:        if (error) {
        !           678:                *error = NULL;
        !           679:        }
        !           680: 
        !           681:        /* check for ?>\n and increment accordingly */
        !           682:        if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
        !           683:                MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
        !           684:        }
        !           685: 
        !           686:        buffer = b32;
        !           687: 
        !           688:        if (3 != php_stream_read(fp, buffer, 3)) {
        !           689:                MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
        !           690:        }
        !           691: 
        !           692:        if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
        !           693:                int nextchar;
        !           694:                halt_offset += 3;
        !           695:                if (EOF == (nextchar = php_stream_getc(fp))) {
        !           696:                        MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
        !           697:                }
        !           698: 
        !           699:                if ((char) nextchar == '\r') {
        !           700:                        /* if we have an \r we require an \n as well */
        !           701:                        if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
        !           702:                                MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
        !           703:                        }
        !           704:                        ++halt_offset;
        !           705:                }
        !           706: 
        !           707:                if ((char) nextchar == '\n') {
        !           708:                        ++halt_offset;
        !           709:                }
        !           710:        }
        !           711: 
        !           712:        /* make sure we are at the right location to read the manifest */
        !           713:        if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
        !           714:                MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
        !           715:        }
        !           716: 
        !           717:        /* read in manifest */
        !           718:        buffer = b32;
        !           719: 
        !           720:        if (4 != php_stream_read(fp, buffer, 4)) {
        !           721:                MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
        !           722:        }
        !           723: 
        !           724:        PHAR_GET_32(buffer, manifest_len);
        !           725: 
        !           726:        if (manifest_len > 1048576 * 100) {
        !           727:                /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
        !           728:                MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
        !           729:        }
        !           730: 
        !           731:        buffer = (char *)emalloc(manifest_len);
        !           732:        savebuf = buffer;
        !           733:        endbuffer = buffer + manifest_len;
        !           734: 
        !           735:        if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
        !           736:                MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
        !           737:        }
        !           738: 
        !           739:        /* extract the number of entries */
        !           740:        PHAR_GET_32(buffer, manifest_count);
        !           741: 
        !           742:        if (manifest_count == 0) {
        !           743:                MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries.  Phars must have at least 1 entry");
        !           744:        }
        !           745: 
        !           746:        /* extract API version, lowest nibble currently unused */
        !           747:        manifest_ver = (((unsigned char)buffer[0]) << 8)
        !           748:                                 + ((unsigned char)buffer[1]);
        !           749:        buffer += 2;
        !           750: 
        !           751:        if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
        !           752:                efree(savebuf);
        !           753:                php_stream_close(fp);
        !           754:                if (error) {
        !           755:                        spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
        !           756:                }
        !           757:                return FAILURE;
        !           758:        }
        !           759: 
        !           760:        PHAR_GET_32(buffer, manifest_flags);
        !           761: 
        !           762:        manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
        !           763:        manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
        !           764:        /* remember whether this entire phar was compressed with gz/bzip2 */
        !           765:        manifest_flags |= compression;
        !           766: 
        !           767:        /* The lowest nibble contains the phar wide flags. The compression flags can */
        !           768:        /* be ignored on reading because it is being generated anyways. */
        !           769:        if (manifest_flags & PHAR_HDR_SIGNATURE) {
        !           770:                char sig_buf[8], *sig_ptr = sig_buf;
        !           771:                off_t read_len;
        !           772:                size_t end_of_phar;
        !           773: 
        !           774:                if (-1 == php_stream_seek(fp, -8, SEEK_END)
        !           775:                || (read_len = php_stream_tell(fp)) < 20
        !           776:                || 8 != php_stream_read(fp, sig_buf, 8)
        !           777:                || memcmp(sig_buf+4, "GBMB", 4)) {
        !           778:                        efree(savebuf);
        !           779:                        php_stream_close(fp);
        !           780:                        if (error) {
        !           781:                                spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
        !           782:                        }
        !           783:                        return FAILURE;
        !           784:                }
        !           785: 
        !           786:                PHAR_GET_32(sig_ptr, sig_flags);
        !           787: 
        !           788:                switch(sig_flags) {
        !           789:                        case PHAR_SIG_OPENSSL: {
        !           790:                                php_uint32 signature_len;
        !           791:                                char *sig;
        !           792:                                off_t whence;
        !           793: 
        !           794:                                /* we store the signature followed by the signature length */
        !           795:                                if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
        !           796:                                || 4 != php_stream_read(fp, sig_buf, 4)) {
        !           797:                                        efree(savebuf);
        !           798:                                        php_stream_close(fp);
        !           799:                                        if (error) {
        !           800:                                                spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
        !           801:                                        }
        !           802:                                        return FAILURE;
        !           803:                                }
        !           804: 
        !           805:                                sig_ptr = sig_buf;
        !           806:                                PHAR_GET_32(sig_ptr, signature_len);
        !           807:                                sig = (char *) emalloc(signature_len);
        !           808:                                whence = signature_len + 4;
        !           809:                                whence = -whence;
        !           810: 
        !           811:                                if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
        !           812:                                || !(end_of_phar = php_stream_tell(fp))
        !           813:                                || signature_len != php_stream_read(fp, sig, signature_len)) {
        !           814:                                        efree(savebuf);
        !           815:                                        efree(sig);
        !           816:                                        php_stream_close(fp);
        !           817:                                        if (error) {
        !           818:                                                spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
        !           819:                                        }
        !           820:                                        return FAILURE;
        !           821:                                }
        !           822: 
        !           823:                                if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error TSRMLS_CC)) {
        !           824:                                        efree(savebuf);
        !           825:                                        efree(sig);
        !           826:                                        php_stream_close(fp);
        !           827:                                        if (error) {
        !           828:                                                char *save = *error;
        !           829:                                                spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
        !           830:                                                efree(save);
        !           831:                                        }
        !           832:                                        return FAILURE;
        !           833:                                }
        !           834:                                efree(sig);
        !           835:                        }
        !           836:                        break;
        !           837: #if PHAR_HASH_OK
        !           838:                        case PHAR_SIG_SHA512: {
        !           839:                                unsigned char digest[64];
        !           840: 
        !           841:                                php_stream_seek(fp, -(8 + 64), SEEK_END);
        !           842:                                read_len = php_stream_tell(fp);
        !           843: 
        !           844:                                if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
        !           845:                                        efree(savebuf);
        !           846:                                        php_stream_close(fp);
        !           847:                                        if (error) {
        !           848:                                                spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
        !           849:                                        }
        !           850:                                        return FAILURE;
        !           851:                                }
        !           852: 
        !           853:                                if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error TSRMLS_CC)) {
        !           854:                                        efree(savebuf);
        !           855:                                        php_stream_close(fp);
        !           856:                                        if (error) {
        !           857:                                                char *save = *error;
        !           858:                                                spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
        !           859:                                                efree(save);
        !           860:                                        }
        !           861:                                        return FAILURE;
        !           862:                                }
        !           863:                                break;
        !           864:                        }
        !           865:                        case PHAR_SIG_SHA256: {
        !           866:                                unsigned char digest[32];
        !           867: 
        !           868:                                php_stream_seek(fp, -(8 + 32), SEEK_END);
        !           869:                                read_len = php_stream_tell(fp);
        !           870: 
        !           871:                                if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
        !           872:                                        efree(savebuf);
        !           873:                                        php_stream_close(fp);
        !           874:                                        if (error) {
        !           875:                                                spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
        !           876:                                        }
        !           877:                                        return FAILURE;
        !           878:                                }
        !           879: 
        !           880:                                if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error TSRMLS_CC)) {
        !           881:                                        efree(savebuf);
        !           882:                                        php_stream_close(fp);
        !           883:                                        if (error) {
        !           884:                                                char *save = *error;
        !           885:                                                spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
        !           886:                                                efree(save);
        !           887:                                        }
        !           888:                                        return FAILURE;
        !           889:                                }
        !           890:                                break;
        !           891:                        }
        !           892: #else
        !           893:                        case PHAR_SIG_SHA512:
        !           894:                        case PHAR_SIG_SHA256:
        !           895:                                efree(savebuf);
        !           896:                                php_stream_close(fp);
        !           897: 
        !           898:                                if (error) {
        !           899:                                        spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
        !           900:                                }
        !           901:                                return FAILURE;
        !           902: #endif
        !           903:                        case PHAR_SIG_SHA1: {
        !           904:                                unsigned char digest[20];
        !           905: 
        !           906:                                php_stream_seek(fp, -(8 + 20), SEEK_END);
        !           907:                                read_len = php_stream_tell(fp);
        !           908: 
        !           909:                                if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
        !           910:                                        efree(savebuf);
        !           911:                                        php_stream_close(fp);
        !           912:                                        if (error) {
        !           913:                                                spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
        !           914:                                        }
        !           915:                                        return FAILURE;
        !           916:                                }
        !           917: 
        !           918:                                if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error TSRMLS_CC)) {
        !           919:                                        efree(savebuf);
        !           920:                                        php_stream_close(fp);
        !           921:                                        if (error) {
        !           922:                                                char *save = *error;
        !           923:                                                spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
        !           924:                                                efree(save);
        !           925:                                        }
        !           926:                                        return FAILURE;
        !           927:                                }
        !           928:                                break;
        !           929:                        }
        !           930:                        case PHAR_SIG_MD5: {
        !           931:                                unsigned char digest[16];
        !           932: 
        !           933:                                php_stream_seek(fp, -(8 + 16), SEEK_END);
        !           934:                                read_len = php_stream_tell(fp);
        !           935: 
        !           936:                                if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
        !           937:                                        efree(savebuf);
        !           938:                                        php_stream_close(fp);
        !           939:                                        if (error) {
        !           940:                                                spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
        !           941:                                        }
        !           942:                                        return FAILURE;
        !           943:                                }
        !           944: 
        !           945:                                if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error TSRMLS_CC)) {
        !           946:                                        efree(savebuf);
        !           947:                                        php_stream_close(fp);
        !           948:                                        if (error) {
        !           949:                                                char *save = *error;
        !           950:                                                spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
        !           951:                                                efree(save);
        !           952:                                        }
        !           953:                                        return FAILURE;
        !           954:                                }
        !           955:                                break;
        !           956:                        }
        !           957:                        default:
        !           958:                                efree(savebuf);
        !           959:                                php_stream_close(fp);
        !           960: 
        !           961:                                if (error) {
        !           962:                                        spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
        !           963:                                }
        !           964:                                return FAILURE;
        !           965:                }
        !           966:        } else if (PHAR_G(require_hash)) {
        !           967:                efree(savebuf);
        !           968:                php_stream_close(fp);
        !           969: 
        !           970:                if (error) {
        !           971:                        spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
        !           972:                }
        !           973:                return FAILURE;
        !           974:        } else {
        !           975:                sig_flags = 0;
        !           976:                sig_len = 0;
        !           977:        }
        !           978: 
        !           979:        /* extract alias */
        !           980:        PHAR_GET_32(buffer, tmp_len);
        !           981: 
        !           982:        if (buffer + tmp_len > endbuffer) {
        !           983:                MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
        !           984:        }
        !           985: 
        !           986:        if (manifest_len < 10 + tmp_len) {
        !           987:                MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
        !           988:        }
        !           989: 
        !           990:        /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
        !           991:        if (tmp_len) {
        !           992:                /* if the alias is stored we enforce it (implicit overrides explicit) */
        !           993:                if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
        !           994:                {
        !           995:                        buffer[tmp_len] = '\0';
        !           996:                        php_stream_close(fp);
        !           997: 
        !           998:                        if (signature) {
        !           999:                                efree(signature);
        !          1000:                        }
        !          1001: 
        !          1002:                        if (error) {
        !          1003:                                spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
        !          1004:                        }
        !          1005: 
        !          1006:                        efree(savebuf);
        !          1007:                        return FAILURE;
        !          1008:                }
        !          1009: 
        !          1010:                alias_len = tmp_len;
        !          1011:                alias = buffer;
        !          1012:                buffer += tmp_len;
        !          1013:                register_alias = 1;
        !          1014:        } else if (!alias_len || !alias) {
        !          1015:                /* if we neither have an explicit nor an implicit alias, we use the filename */
        !          1016:                alias = NULL;
        !          1017:                alias_len = 0;
        !          1018:                register_alias = 0;
        !          1019:        } else if (alias_len) {
        !          1020:                register_alias = 1;
        !          1021:                temp_alias = 1;
        !          1022:        }
        !          1023: 
        !          1024:        /* we have 5 32-bit items plus 1 byte at least */
        !          1025:        if (manifest_count > ((manifest_len - 10 - tmp_len) / (5 * 4 + 1))) {
        !          1026:                /* prevent serious memory issues */
        !          1027:                MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
        !          1028:        }
        !          1029: 
        !          1030:        mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
        !          1031:        mydata->is_persistent = PHAR_G(persist);
        !          1032: 
        !          1033:        /* check whether we have meta data, zero check works regardless of byte order */
        !          1034:        if (mydata->is_persistent) {
        !          1035:                PHAR_GET_32(buffer, mydata->metadata_len);
        !          1036:                if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) {
        !          1037:                        MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
        !          1038:                }
        !          1039:        } else {
        !          1040:                if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
        !          1041:                        MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
        !          1042:                }
        !          1043:        }
        !          1044: 
        !          1045:        /* set up our manifest */
        !          1046:        zend_hash_init(&mydata->manifest, manifest_count,
        !          1047:                zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
        !          1048:        zend_hash_init(&mydata->mounted_dirs, 5,
        !          1049:                zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
        !          1050:        zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
        !          1051:                zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
        !          1052:        mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
        !          1053: #ifdef PHP_WIN32
        !          1054:        phar_unixify_path_separators(mydata->fname, fname_len);
        !          1055: #endif
        !          1056:        mydata->fname_len = fname_len;
        !          1057:        offset = halt_offset + manifest_len + 4;
        !          1058:        memset(&entry, 0, sizeof(phar_entry_info));
        !          1059:        entry.phar = mydata;
        !          1060:        entry.fp_type = PHAR_FP;
        !          1061:        entry.is_persistent = mydata->is_persistent;
        !          1062: 
        !          1063:        for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
        !          1064:                if (buffer + 4 > endbuffer) {
        !          1065:                        MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
        !          1066:                }
        !          1067: 
        !          1068:                PHAR_GET_32(buffer, entry.filename_len);
        !          1069: 
        !          1070:                if (entry.filename_len == 0) {
        !          1071:                        MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
        !          1072:                }
        !          1073: 
        !          1074:                if (entry.is_persistent) {
        !          1075:                        entry.manifest_pos = manifest_index;
        !          1076:                }
        !          1077: 
        !          1078:                if (buffer + entry.filename_len + 20 > endbuffer) {
        !          1079:                        MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
        !          1080:                }
        !          1081: 
        !          1082:                if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
        !          1083:                        entry.is_dir = 1;
        !          1084:                } else {
        !          1085:                        entry.is_dir = 0;
        !          1086:                }
        !          1087: 
        !          1088:                phar_add_virtual_dirs(mydata, buffer, entry.filename_len TSRMLS_CC);
        !          1089:                entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
        !          1090:                buffer += entry.filename_len;
        !          1091:                PHAR_GET_32(buffer, entry.uncompressed_filesize);
        !          1092:                PHAR_GET_32(buffer, entry.timestamp);
        !          1093: 
        !          1094:                if (offset == halt_offset + (int)manifest_len + 4) {
        !          1095:                        mydata->min_timestamp = entry.timestamp;
        !          1096:                        mydata->max_timestamp = entry.timestamp;
        !          1097:                } else {
        !          1098:                        if (mydata->min_timestamp > entry.timestamp) {
        !          1099:                                mydata->min_timestamp = entry.timestamp;
        !          1100:                        } else if (mydata->max_timestamp < entry.timestamp) {
        !          1101:                                mydata->max_timestamp = entry.timestamp;
        !          1102:                        }
        !          1103:                }
        !          1104: 
        !          1105:                PHAR_GET_32(buffer, entry.compressed_filesize);
        !          1106:                PHAR_GET_32(buffer, entry.crc32);
        !          1107:                PHAR_GET_32(buffer, entry.flags);
        !          1108: 
        !          1109:                if (entry.is_dir) {
        !          1110:                        entry.filename_len--;
        !          1111:                        entry.flags |= PHAR_ENT_PERM_DEF_DIR;
        !          1112:                }
        !          1113: 
        !          1114:                if (entry.is_persistent) {
        !          1115:                        PHAR_GET_32(buffer, entry.metadata_len);
        !          1116:                        if (!entry.metadata_len) buffer -= 4;
        !          1117:                        if (phar_parse_metadata(&buffer, &entry.metadata, entry.metadata_len TSRMLS_CC) == FAILURE) {
        !          1118:                                pefree(entry.filename, entry.is_persistent);
        !          1119:                                MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
        !          1120:                        }
        !          1121:                } else {
        !          1122:                        if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
        !          1123:                                pefree(entry.filename, entry.is_persistent);
        !          1124:                                MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
        !          1125:                        }
        !          1126:                }
        !          1127: 
        !          1128:                entry.offset = entry.offset_abs = offset;
        !          1129:                offset += entry.compressed_filesize;
        !          1130: 
        !          1131:                switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
        !          1132:                        case PHAR_ENT_COMPRESSED_GZ:
        !          1133:                                if (!PHAR_G(has_zlib)) {
        !          1134:                                        if (entry.metadata) {
        !          1135:                                                if (entry.is_persistent) {
        !          1136:                                                        free(entry.metadata);
        !          1137:                                                } else {
        !          1138:                                                        zval_ptr_dtor(&entry.metadata);
        !          1139:                                                }
        !          1140:                                        }
        !          1141:                                        pefree(entry.filename, entry.is_persistent);
        !          1142:                                        MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
        !          1143:                                }
        !          1144:                                break;
        !          1145:                        case PHAR_ENT_COMPRESSED_BZ2:
        !          1146:                                if (!PHAR_G(has_bz2)) {
        !          1147:                                        if (entry.metadata) {
        !          1148:                                                if (entry.is_persistent) {
        !          1149:                                                        free(entry.metadata);
        !          1150:                                                } else {
        !          1151:                                                        zval_ptr_dtor(&entry.metadata);
        !          1152:                                                }
        !          1153:                                        }
        !          1154:                                        pefree(entry.filename, entry.is_persistent);
        !          1155:                                        MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
        !          1156:                                }
        !          1157:                                break;
        !          1158:                        default:
        !          1159:                                if (entry.uncompressed_filesize != entry.compressed_filesize) {
        !          1160:                                        if (entry.metadata) {
        !          1161:                                                if (entry.is_persistent) {
        !          1162:                                                        free(entry.metadata);
        !          1163:                                                } else {
        !          1164:                                                        zval_ptr_dtor(&entry.metadata);
        !          1165:                                                }
        !          1166:                                        }
        !          1167:                                        pefree(entry.filename, entry.is_persistent);
        !          1168:                                        MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
        !          1169:                                }
        !          1170:                                break;
        !          1171:                }
        !          1172: 
        !          1173:                manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
        !          1174:                /* if signature matched, no need to check CRC32 for each file */
        !          1175:                entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
        !          1176:                phar_set_inode(&entry TSRMLS_CC);
        !          1177:                zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
        !          1178:        }
        !          1179: 
        !          1180:        snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
        !          1181:        mydata->internal_file_start = halt_offset + manifest_len + 4;
        !          1182:        mydata->halt_offset = halt_offset;
        !          1183:        mydata->flags = manifest_flags;
        !          1184:        endbuffer = strrchr(mydata->fname, '/');
        !          1185: 
        !          1186:        if (endbuffer) {
        !          1187:                mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
        !          1188:                if (mydata->ext == endbuffer) {
        !          1189:                        mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
        !          1190:                }
        !          1191:                if (mydata->ext) {
        !          1192:                        mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
        !          1193:                }
        !          1194:        }
        !          1195: 
        !          1196:        mydata->alias = alias ?
        !          1197:                pestrndup(alias, alias_len, mydata->is_persistent) :
        !          1198:                pestrndup(mydata->fname, fname_len, mydata->is_persistent);
        !          1199:        mydata->alias_len = alias ? alias_len : fname_len;
        !          1200:        mydata->sig_flags = sig_flags;
        !          1201:        mydata->fp = fp;
        !          1202:        mydata->sig_len = sig_len;
        !          1203:        mydata->signature = signature;
        !          1204:        phar_request_initialize(TSRMLS_C);
        !          1205: 
        !          1206:        if (register_alias) {
        !          1207:                phar_archive_data **fd_ptr;
        !          1208: 
        !          1209:                mydata->is_temporary_alias = temp_alias;
        !          1210: 
        !          1211:                if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
        !          1212:                        signature = NULL;
        !          1213:                        fp = NULL;
        !          1214:                        MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
        !          1215:                }
        !          1216: 
        !          1217:                if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
        !          1218:                        if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
        !          1219:                                signature = NULL;
        !          1220:                                fp = NULL;
        !          1221:                                MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
        !          1222:                        }
        !          1223:                }
        !          1224: 
        !          1225:                zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
        !          1226:        } else {
        !          1227:                mydata->is_temporary_alias = 1;
        !          1228:        }
        !          1229: 
        !          1230:        zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*),  NULL);
        !          1231:        efree(savebuf);
        !          1232: 
        !          1233:        if (pphar) {
        !          1234:                *pphar = mydata;
        !          1235:        }
        !          1236: 
        !          1237:        return SUCCESS;
        !          1238: }
        !          1239: /* }}} */
        !          1240: 
        !          1241: /**
        !          1242:  * Create or open a phar for writing
        !          1243:  */
        !          1244: int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
        !          1245: {
        !          1246:        const char *ext_str, *z;
        !          1247:        char *my_error;
        !          1248:        int ext_len;
        !          1249:        phar_archive_data **test, *unused = NULL;
        !          1250: 
        !          1251:        test = &unused;
        !          1252: 
        !          1253:        if (error) {
        !          1254:                *error = NULL;
        !          1255:        }
        !          1256: 
        !          1257:        /* first try to open an existing file */
        !          1258:        if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
        !          1259:                goto check_file;
        !          1260:        }
        !          1261: 
        !          1262:        /* next try to create a new file */
        !          1263:        if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
        !          1264:                if (error) {
        !          1265:                        if (ext_len == -2) {
        !          1266:                                spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
        !          1267:                        } else {
        !          1268:                                spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
        !          1269:                        }
        !          1270:                }
        !          1271:                return FAILURE;
        !          1272:        }
        !          1273: check_file:
        !          1274:        if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
        !          1275:                if (pphar) {
        !          1276:                        *pphar = *test;
        !          1277:                }
        !          1278: 
        !          1279:                if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
        !          1280:                        if (error) {
        !          1281:                                spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
        !          1282:                        }
        !          1283:                        return FAILURE;
        !          1284:                }
        !          1285: 
        !          1286:                if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
        !          1287:                        phar_entry_info *stub;
        !          1288:                        if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
        !          1289:                                spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
        !          1290:                                return FAILURE;
        !          1291:                        }
        !          1292:                }
        !          1293: 
        !          1294:                if (!PHAR_G(readonly) || (*test)->is_data) {
        !          1295:                        (*test)->is_writeable = 1;
        !          1296:                }
        !          1297:                return SUCCESS;
        !          1298:        } else if (my_error) {
        !          1299:                if (error) {
        !          1300:                        *error = my_error;
        !          1301:                } else {
        !          1302:                        efree(my_error);
        !          1303:                }
        !          1304:                return FAILURE;
        !          1305:        }
        !          1306: 
        !          1307:        if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
        !          1308:                /* assume zip-based phar */
        !          1309:                return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
        !          1310:        }
        !          1311: 
        !          1312:        if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
        !          1313:                /* assume tar-based phar */
        !          1314:                return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
        !          1315:        }
        !          1316: 
        !          1317:        return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
        !          1318: }
        !          1319: /* }}} */
        !          1320: 
        !          1321: int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
        !          1322: {
        !          1323:        phar_archive_data *mydata;
        !          1324:        php_stream *fp;
        !          1325:        char *actual = NULL, *p;
        !          1326: 
        !          1327:        if (!pphar) {
        !          1328:                pphar = &mydata;
        !          1329:        }
        !          1330: #if PHP_API_VERSION < 20100412
        !          1331:        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
        !          1332:                return FAILURE;
        !          1333:        }
        !          1334: #endif
        !          1335:        if (php_check_open_basedir(fname TSRMLS_CC)) {
        !          1336:                return FAILURE;
        !          1337:        }
        !          1338: 
        !          1339:        /* first open readonly so it won't be created if not present */
        !          1340:        fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
        !          1341: 
        !          1342:        if (actual) {
        !          1343:                fname = actual;
        !          1344:                fname_len = strlen(actual);
        !          1345:        }
        !          1346: 
        !          1347:        if (fp) {
        !          1348:                if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC) == SUCCESS) {
        !          1349:                        if ((*pphar)->is_data || !PHAR_G(readonly)) {
        !          1350:                                (*pphar)->is_writeable = 1;
        !          1351:                        }
        !          1352:                        if (actual) {
        !          1353:                                efree(actual);
        !          1354:                        }
        !          1355:                        return SUCCESS;
        !          1356:                } else {
        !          1357:                        /* file exists, but is either corrupt or not a phar archive */
        !          1358:                        if (actual) {
        !          1359:                                efree(actual);
        !          1360:                        }
        !          1361:                        return FAILURE;
        !          1362:                }
        !          1363:        }
        !          1364: 
        !          1365:        if (actual) {
        !          1366:                efree(actual);
        !          1367:        }
        !          1368: 
        !          1369:        if (PHAR_G(readonly) && !is_data) {
        !          1370:                if (options & REPORT_ERRORS) {
        !          1371:                        if (error) {
        !          1372:                                spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
        !          1373:                        }
        !          1374:                }
        !          1375:                return FAILURE;
        !          1376:        }
        !          1377: 
        !          1378:        /* set up our manifest */
        !          1379:        mydata = ecalloc(1, sizeof(phar_archive_data));
        !          1380:        mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
        !          1381:        fname_len = strlen(mydata->fname);
        !          1382: #ifdef PHP_WIN32
        !          1383:        phar_unixify_path_separators(mydata->fname, fname_len);
        !          1384: #endif
        !          1385:        p = strrchr(mydata->fname, '/');
        !          1386: 
        !          1387:        if (p) {
        !          1388:                mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
        !          1389:                if (mydata->ext == p) {
        !          1390:                        mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
        !          1391:                }
        !          1392:                if (mydata->ext) {
        !          1393:                        mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
        !          1394:                }
        !          1395:        }
        !          1396: 
        !          1397:        if (pphar) {
        !          1398:                *pphar = mydata;
        !          1399:        }
        !          1400: 
        !          1401:        zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
        !          1402:                zend_get_hash_value, destroy_phar_manifest_entry, 0);
        !          1403:        zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
        !          1404:                zend_get_hash_value, NULL, 0);
        !          1405:        zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
        !          1406:                zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
        !          1407:        mydata->fname_len = fname_len;
        !          1408:        snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
        !          1409:        mydata->is_temporary_alias = alias ? 0 : 1;
        !          1410:        mydata->internal_file_start = -1;
        !          1411:        mydata->fp = NULL;
        !          1412:        mydata->is_writeable = 1;
        !          1413:        mydata->is_brandnew = 1;
        !          1414:        phar_request_initialize(TSRMLS_C);
        !          1415:        zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*),  NULL);
        !          1416: 
        !          1417:        if (is_data) {
        !          1418:                alias = NULL;
        !          1419:                alias_len = 0;
        !          1420:                mydata->is_data = 1;
        !          1421:                /* assume tar format, PharData can specify other */
        !          1422:                mydata->is_tar = 1;
        !          1423:        } else {
        !          1424:                phar_archive_data **fd_ptr;
        !          1425: 
        !          1426:                if (alias && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
        !          1427:                        if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
        !          1428:                                if (error) {
        !          1429:                                        spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
        !          1430:                                }
        !          1431: 
        !          1432:                                zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
        !          1433: 
        !          1434:                                if (pphar) {
        !          1435:                                        *pphar = NULL;
        !          1436:                                }
        !          1437: 
        !          1438:                                return FAILURE;
        !          1439:                        }
        !          1440:                }
        !          1441: 
        !          1442:                mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
        !          1443:                mydata->alias_len = alias ? alias_len : fname_len;
        !          1444:        }
        !          1445: 
        !          1446:        if (alias_len && alias) {
        !          1447:                if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
        !          1448:                        if (options & REPORT_ERRORS) {
        !          1449:                                if (error) {
        !          1450:                                        spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
        !          1451:                                }
        !          1452:                        }
        !          1453: 
        !          1454:                        zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
        !          1455: 
        !          1456:                        if (pphar) {
        !          1457:                                *pphar = NULL;
        !          1458:                        }
        !          1459: 
        !          1460:                        return FAILURE;
        !          1461:                }
        !          1462:        }
        !          1463: 
        !          1464:        return SUCCESS;
        !          1465: }
        !          1466: /* }}}*/
        !          1467: 
        !          1468: /**
        !          1469:  * Return an already opened filename.
        !          1470:  *
        !          1471:  * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
        !          1472:  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
        !          1473:  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
        !          1474:  */
        !          1475: int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
        !          1476: {
        !          1477:        php_stream *fp;
        !          1478:        char *actual;
        !          1479:        int ret, is_data = 0;
        !          1480: 
        !          1481:        if (error) {
        !          1482:                *error = NULL;
        !          1483:        }
        !          1484: 
        !          1485:        if (!strstr(fname, ".phar")) {
        !          1486:                is_data = 1;
        !          1487:        }
        !          1488: 
        !          1489:        if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) {
        !          1490:                return SUCCESS;
        !          1491:        } else if (error && *error) {
        !          1492:                return FAILURE;
        !          1493:        }
        !          1494: #if PHP_API_VERSION < 20100412
        !          1495:        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
        !          1496:                return FAILURE;
        !          1497:        }
        !          1498: #endif
        !          1499:        if (php_check_open_basedir(fname TSRMLS_CC)) {
        !          1500:                return FAILURE;
        !          1501:        }
        !          1502: 
        !          1503:        fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
        !          1504: 
        !          1505:        if (!fp) {
        !          1506:                if (options & REPORT_ERRORS) {
        !          1507:                        if (error) {
        !          1508:                                spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
        !          1509:                        }
        !          1510:                }
        !          1511:                if (actual) {
        !          1512:                        efree(actual);
        !          1513:                }
        !          1514:                return FAILURE;
        !          1515:        }
        !          1516: 
        !          1517:        if (actual) {
        !          1518:                fname = actual;
        !          1519:                fname_len = strlen(actual);
        !          1520:        }
        !          1521: 
        !          1522:        ret =  phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC);
        !          1523: 
        !          1524:        if (actual) {
        !          1525:                efree(actual);
        !          1526:        }
        !          1527: 
        !          1528:        return ret;
        !          1529: }
        !          1530: /* }}}*/
        !          1531: 
        !          1532: static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
        !          1533: {
        !          1534:        const char *c;
        !          1535:        int so_far = 0;
        !          1536: 
        !          1537:        if (buf_len < search_len) {
        !          1538:                return NULL;
        !          1539:        }
        !          1540: 
        !          1541:        c = buf - 1;
        !          1542: 
        !          1543:        do {
        !          1544:                if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
        !          1545:                        return (char *) NULL;
        !          1546:                }
        !          1547: 
        !          1548:                so_far = c - buf;
        !          1549: 
        !          1550:                if (so_far >= (buf_len - search_len)) {
        !          1551:                        return (char *) NULL;
        !          1552:                }
        !          1553: 
        !          1554:                if (!memcmp(c, search, search_len)) {
        !          1555:                        return (char *) c;
        !          1556:                }
        !          1557:        } while (1);
        !          1558: }
        !          1559: /* }}} */
        !          1560: 
        !          1561: /**
        !          1562:  * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
        !          1563:  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
        !          1564:  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
        !          1565:  */
        !          1566: static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, int is_data, char **error TSRMLS_DC) /* {{{ */
        !          1567: {
        !          1568:        const char token[] = "__HALT_COMPILER();";
        !          1569:        const char zip_magic[] = "PK\x03\x04";
        !          1570:        const char gz_magic[] = "\x1f\x8b\x08";
        !          1571:        const char bz_magic[] = "BZh";
        !          1572:        char *pos, test = '\0';
        !          1573:        const int window_size = 1024;
        !          1574:        char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
        !          1575:        const long readsize = sizeof(buffer) - sizeof(token);
        !          1576:        const long tokenlen = sizeof(token) - 1;
        !          1577:        long halt_offset;
        !          1578:        size_t got;
        !          1579:        php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
        !          1580: 
        !          1581:        if (error) {
        !          1582:                *error = NULL;
        !          1583:        }
        !          1584: 
        !          1585:        if (-1 == php_stream_rewind(fp)) {
        !          1586:                MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
        !          1587:        }
        !          1588: 
        !          1589:        buffer[sizeof(buffer)-1] = '\0';
        !          1590:        memset(buffer, 32, sizeof(token));
        !          1591:        halt_offset = 0;
        !          1592: 
        !          1593:        /* Maybe it's better to compile the file instead of just searching,  */
        !          1594:        /* but we only want the offset. So we want a .re scanner to find it. */
        !          1595:        while(!php_stream_eof(fp)) {
        !          1596:                if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
        !          1597:                        MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
        !          1598:                }
        !          1599: 
        !          1600:                if (!test) {
        !          1601:                        test = '\1';
        !          1602:                        pos = buffer+tokenlen;
        !          1603:                        if (!memcmp(pos, gz_magic, 3)) {
        !          1604:                                char err = 0;
        !          1605:                                php_stream_filter *filter;
        !          1606:                                php_stream *temp;
        !          1607:                                /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
        !          1608:                                zval filterparams;
        !          1609: 
        !          1610:                                if (!PHAR_G(has_zlib)) {
        !          1611:                                        MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
        !          1612:                                }
        !          1613:                                array_init(&filterparams);
        !          1614: /* this is defined in zlib's zconf.h */
        !          1615: #ifndef MAX_WBITS
        !          1616: #define MAX_WBITS 15
        !          1617: #endif
        !          1618:                                add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
        !          1619: 
        !          1620:                                /* entire file is gzip-compressed, uncompress to temporary file */
        !          1621:                                if (!(temp = php_stream_fopen_tmpfile())) {
        !          1622:                                        MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
        !          1623:                                }
        !          1624: 
        !          1625:                                php_stream_rewind(fp);
        !          1626:                                filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
        !          1627: 
        !          1628:                                if (!filter) {
        !          1629:                                        err = 1;
        !          1630:                                        add_assoc_long(&filterparams, "window", MAX_WBITS);
        !          1631:                                        filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
        !          1632:                                        zval_dtor(&filterparams);
        !          1633: 
        !          1634:                                        if (!filter) {
        !          1635:                                                php_stream_close(temp);
        !          1636:                                                MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
        !          1637:                                        }
        !          1638:                                } else {
        !          1639:                                        zval_dtor(&filterparams);
        !          1640:                                }
        !          1641: 
        !          1642:                                php_stream_filter_append(&temp->writefilters, filter);
        !          1643: 
        !          1644:                                if (SUCCESS != phar_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
        !          1645:                                        if (err) {
        !          1646:                                                php_stream_close(temp);
        !          1647:                                                MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
        !          1648:                                        }
        !          1649:                                        php_stream_close(temp);
        !          1650:                                        MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
        !          1651:                                }
        !          1652: 
        !          1653:                                php_stream_filter_flush(filter, 1);
        !          1654:                                php_stream_filter_remove(filter, 1 TSRMLS_CC);
        !          1655:                                php_stream_close(fp);
        !          1656:                                fp = temp;
        !          1657:                                php_stream_rewind(fp);
        !          1658:                                compression = PHAR_FILE_COMPRESSED_GZ;
        !          1659: 
        !          1660:                                /* now, start over */
        !          1661:                                test = '\0';
        !          1662:                                continue;
        !          1663:                        } else if (!memcmp(pos, bz_magic, 3)) {
        !          1664:                                php_stream_filter *filter;
        !          1665:                                php_stream *temp;
        !          1666: 
        !          1667:                                if (!PHAR_G(has_bz2)) {
        !          1668:                                        MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
        !          1669:                                }
        !          1670: 
        !          1671:                                /* entire file is bzip-compressed, uncompress to temporary file */
        !          1672:                                if (!(temp = php_stream_fopen_tmpfile())) {
        !          1673:                                        MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
        !          1674:                                }
        !          1675: 
        !          1676:                                php_stream_rewind(fp);
        !          1677:                                filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
        !          1678: 
        !          1679:                                if (!filter) {
        !          1680:                                        php_stream_close(temp);
        !          1681:                                        MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
        !          1682:                                }
        !          1683: 
        !          1684:                                php_stream_filter_append(&temp->writefilters, filter);
        !          1685: 
        !          1686:                                if (SUCCESS != phar_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
        !          1687:                                        php_stream_close(temp);
        !          1688:                                        MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
        !          1689:                                }
        !          1690: 
        !          1691:                                php_stream_filter_flush(filter, 1);
        !          1692:                                php_stream_filter_remove(filter, 1 TSRMLS_CC);
        !          1693:                                php_stream_close(fp);
        !          1694:                                fp = temp;
        !          1695:                                php_stream_rewind(fp);
        !          1696:                                compression = PHAR_FILE_COMPRESSED_BZ2;
        !          1697: 
        !          1698:                                /* now, start over */
        !          1699:                                test = '\0';
        !          1700:                                continue;
        !          1701:                        }
        !          1702: 
        !          1703:                        if (!memcmp(pos, zip_magic, 4)) {
        !          1704:                                php_stream_seek(fp, 0, SEEK_END);
        !          1705:                                return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
        !          1706:                        }
        !          1707: 
        !          1708:                        if (got > 512) {
        !          1709:                                if (phar_is_tar(pos, fname)) {
        !          1710:                                        php_stream_rewind(fp);
        !          1711:                                        return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error TSRMLS_CC);
        !          1712:                                }
        !          1713:                        }
        !          1714:                }
        !          1715: 
        !          1716:                if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
        !          1717:                        halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
        !          1718:                        return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
        !          1719:                }
        !          1720: 
        !          1721:                halt_offset += got;
        !          1722:                memmove(buffer, buffer + window_size, tokenlen); /* move the memory buffer by the size of the window */
        !          1723:        }
        !          1724: 
        !          1725:        MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
        !          1726: }
        !          1727: /* }}} */
        !          1728: 
        !          1729: /*
        !          1730:  * given the location of the file extension and the start of the file path,
        !          1731:  * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
        !          1732:  * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
        !          1733:  * stat it to determine if it exists.
        !          1734:  * if so, check to see if it is a directory and fail if so
        !          1735:  * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
        !          1736:  * succeed if we are creating the file, otherwise fail.
        !          1737:  */
        !          1738: static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC) /* {{{ */
        !          1739: {
        !          1740:        php_stream_statbuf ssb;
        !          1741:        char *realpath, old, *a = (char *)(ext + ext_len);
        !          1742: 
        !          1743:        old = *a;
        !          1744:        *a = '\0';
        !          1745: 
        !          1746:        if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
        !          1747: #ifdef PHP_WIN32
        !          1748:                phar_unixify_path_separators(realpath, strlen(realpath));
        !          1749: #endif
        !          1750:                if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
        !          1751:                        *a = old;
        !          1752:                        efree(realpath);
        !          1753:                        return SUCCESS;
        !          1754:                }
        !          1755: 
        !          1756:                if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
        !          1757:                        *a = old;
        !          1758:                        efree(realpath);
        !          1759:                        return SUCCESS;
        !          1760:                }
        !          1761:                efree(realpath);
        !          1762:        }
        !          1763: 
        !          1764:        if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) {
        !          1765:                *a = old;
        !          1766: 
        !          1767:                if (ssb.sb.st_mode & S_IFDIR) {
        !          1768:                        return FAILURE;
        !          1769:                }
        !          1770: 
        !          1771:                if (for_create == 1) {
        !          1772:                        return FAILURE;
        !          1773:                }
        !          1774: 
        !          1775:                return SUCCESS;
        !          1776:        } else {
        !          1777:                char *slash;
        !          1778: 
        !          1779:                if (!for_create) {
        !          1780:                        *a = old;
        !          1781:                        return FAILURE;
        !          1782:                }
        !          1783: 
        !          1784:                slash = (char *) strrchr(fname, '/');
        !          1785:                *a = old;
        !          1786: 
        !          1787:                if (slash) {
        !          1788:                        old = *slash;
        !          1789:                        *slash = '\0';
        !          1790:                }
        !          1791: 
        !          1792:                if (SUCCESS != php_stream_stat_path((char *) fname, &ssb)) {
        !          1793:                        if (slash) {
        !          1794:                                *slash = old;
        !          1795:                        } else {
        !          1796:                                if (!(realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
        !          1797:                                        return FAILURE;
        !          1798:                                }
        !          1799: #ifdef PHP_WIN32
        !          1800:                                phar_unixify_path_separators(realpath, strlen(realpath));
        !          1801: #endif
        !          1802:                                a = strstr(realpath, fname) + ((ext - fname) + ext_len);
        !          1803:                                *a = '\0';
        !          1804:                                slash = strrchr(realpath, '/');
        !          1805: 
        !          1806:                                if (slash) {
        !          1807:                                        *slash = '\0';
        !          1808:                                } else {
        !          1809:                                        efree(realpath);
        !          1810:                                        return FAILURE;
        !          1811:                                }
        !          1812: 
        !          1813:                                if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
        !          1814:                                        efree(realpath);
        !          1815:                                        return FAILURE;
        !          1816:                                }
        !          1817: 
        !          1818:                                efree(realpath);
        !          1819: 
        !          1820:                                if (ssb.sb.st_mode & S_IFDIR) {
        !          1821:                                        return SUCCESS;
        !          1822:                                }
        !          1823:                        }
        !          1824: 
        !          1825:                        return FAILURE;
        !          1826:                }
        !          1827: 
        !          1828:                if (slash) {
        !          1829:                        *slash = old;
        !          1830:                }
        !          1831: 
        !          1832:                if (ssb.sb.st_mode & S_IFDIR) {
        !          1833:                        return SUCCESS;
        !          1834:                }
        !          1835: 
        !          1836:                return FAILURE;
        !          1837:        }
        !          1838: }
        !          1839: /* }}} */
        !          1840: 
        !          1841: /* check for ".phar" in extension */
        !          1842: static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC) /* {{{ */
        !          1843: {
        !          1844:        char test[51];
        !          1845:        const char *pos;
        !          1846: 
        !          1847:        if (ext_len >= 50) {
        !          1848:                return FAILURE;
        !          1849:        }
        !          1850: 
        !          1851:        if (executable == 1) {
        !          1852:                /* copy "." as well */
        !          1853:                memcpy(test, ext_str - 1, ext_len + 1);
        !          1854:                test[ext_len + 1] = '\0';
        !          1855:                /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
        !          1856:                /* (phar://hi/there/.phar/oops is also invalid) */
        !          1857:                pos = strstr(test, ".phar");
        !          1858: 
        !          1859:                if (pos && (*(pos - 1) != '/')
        !          1860:                                && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
        !          1861:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
        !          1862:                } else {
        !          1863:                        return FAILURE;
        !          1864:                }
        !          1865:        }
        !          1866: 
        !          1867:        /* data phars need only contain a single non-"." to be valid */
        !          1868:        if (!executable) {
        !          1869:                pos = strstr(ext_str, ".phar");
        !          1870:                if (!(pos && (*(pos - 1) != '/')
        !          1871:                                        && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
        !          1872:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
        !          1873:                }
        !          1874:        } else {
        !          1875:                if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
        !          1876:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
        !          1877:                }
        !          1878:        }
        !          1879: 
        !          1880:        return FAILURE;
        !          1881: }
        !          1882: /* }}} */
        !          1883: 
        !          1884: /*
        !          1885:  * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
        !          1886:  * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
        !          1887:  * the first extension as the filename extension
        !          1888:  *
        !          1889:  * if an extension is found, it sets ext_str to the location of the file extension in filename,
        !          1890:  * and ext_len to the length of the extension.
        !          1891:  * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
        !          1892:  * the calling function to use "alias" as the phar alias
        !          1893:  *
        !          1894:  * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
        !          1895:  * extension rules, not to iterate.
        !          1896:  */
        !          1897: int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC) /* {{{ */
        !          1898: {
        !          1899:        const char *pos, *slash;
        !          1900: 
        !          1901:        *ext_str = NULL;
        !          1902:        *ext_len = 0;
        !          1903: 
        !          1904:        if (!filename_len || filename_len == 1) {
        !          1905:                return FAILURE;
        !          1906:        }
        !          1907: 
        !          1908:        phar_request_initialize(TSRMLS_C);
        !          1909:        /* first check for alias in first segment */
        !          1910:        pos = memchr(filename, '/', filename_len);
        !          1911: 
        !          1912:        if (pos && pos != filename) {
        !          1913:                /* check for url like http:// or phar:// */
        !          1914:                if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
        !          1915:                        *ext_len = -2;
        !          1916:                        *ext_str = NULL;
        !          1917:                        return FAILURE;
        !          1918:                }
        !          1919:                if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
        !          1920:                        *ext_str = pos;
        !          1921:                        *ext_len = -1;
        !          1922:                        return FAILURE;
        !          1923:                }
        !          1924: 
        !          1925:                if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
        !          1926:                        *ext_str = pos;
        !          1927:                        *ext_len = -1;
        !          1928:                        return FAILURE;
        !          1929:                }
        !          1930:        }
        !          1931: 
        !          1932:        if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
        !          1933:                phar_archive_data **pphar;
        !          1934: 
        !          1935:                if (is_complete) {
        !          1936:                        if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) {
        !          1937:                                *ext_str = filename + (filename_len - (*pphar)->ext_len);
        !          1938: woohoo:
        !          1939:                                *ext_len = (*pphar)->ext_len;
        !          1940: 
        !          1941:                                if (executable == 2) {
        !          1942:                                        return SUCCESS;
        !          1943:                                }
        !          1944: 
        !          1945:                                if (executable == 1 && !(*pphar)->is_data) {
        !          1946:                                        return SUCCESS;
        !          1947:                                }
        !          1948: 
        !          1949:                                if (!executable && (*pphar)->is_data) {
        !          1950:                                        return SUCCESS;
        !          1951:                                }
        !          1952: 
        !          1953:                                return FAILURE;
        !          1954:                        }
        !          1955: 
        !          1956:                        if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
        !          1957:                                *ext_str = filename + (filename_len - (*pphar)->ext_len);
        !          1958:                                goto woohoo;
        !          1959:                        }
        !          1960:                } else {
        !          1961:                        phar_zstr key;
        !          1962:                        char *str_key;
        !          1963:                        uint keylen;
        !          1964:                        ulong unused;
        !          1965: 
        !          1966:                        zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
        !          1967: 
        !          1968:                        while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) {
        !          1969:                                if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) {
        !          1970:                                        break;
        !          1971:                                }
        !          1972: 
        !          1973:                                PHAR_STR(key, str_key);
        !          1974: 
        !          1975:                                if (keylen > (uint) filename_len) {
        !          1976:                                        zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
        !          1977:                                        PHAR_STR_FREE(str_key);
        !          1978:                                        continue;
        !          1979:                                }
        !          1980: 
        !          1981:                                if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
        !          1982:                                        || filename[keylen] == '/' || filename[keylen] == '\0')) {
        !          1983:                                        PHAR_STR_FREE(str_key);
        !          1984:                                        if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
        !          1985:                                                break;
        !          1986:                                        }
        !          1987:                                        *ext_str = filename + (keylen - (*pphar)->ext_len);
        !          1988:                                        goto woohoo;
        !          1989:                                }
        !          1990: 
        !          1991:                                PHAR_STR_FREE(str_key);
        !          1992:                                zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
        !          1993:                        }
        !          1994: 
        !          1995:                        if (PHAR_G(manifest_cached)) {
        !          1996:                                zend_hash_internal_pointer_reset(&cached_phars);
        !          1997: 
        !          1998:                                while (FAILURE != zend_hash_has_more_elements(&cached_phars)) {
        !          1999:                                        if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&cached_phars, &key, &keylen, &unused, 0, NULL)) {
        !          2000:                                                break;
        !          2001:                                        }
        !          2002: 
        !          2003:                                        PHAR_STR(key, str_key);
        !          2004: 
        !          2005:                                        if (keylen > (uint) filename_len) {
        !          2006:                                                zend_hash_move_forward(&cached_phars);
        !          2007:                                                PHAR_STR_FREE(str_key);
        !          2008:                                                continue;
        !          2009:                                        }
        !          2010: 
        !          2011:                                        if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
        !          2012:                                                || filename[keylen] == '/' || filename[keylen] == '\0')) {
        !          2013:                                                PHAR_STR_FREE(str_key);
        !          2014:                                                if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
        !          2015:                                                        break;
        !          2016:                                                }
        !          2017:                                                *ext_str = filename + (keylen - (*pphar)->ext_len);
        !          2018:                                                goto woohoo;
        !          2019:                                        }
        !          2020:                                        PHAR_STR_FREE(str_key);
        !          2021:                                        zend_hash_move_forward(&cached_phars);
        !          2022:                                }
        !          2023:                        }
        !          2024:                }
        !          2025:        }
        !          2026: 
        !          2027:        pos = memchr(filename + 1, '.', filename_len);
        !          2028: next_extension:
        !          2029:        if (!pos) {
        !          2030:                return FAILURE;
        !          2031:        }
        !          2032: 
        !          2033:        while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
        !          2034:                pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1);
        !          2035:                if (!pos) {
        !          2036:                        return FAILURE;
        !          2037:                }
        !          2038:        }
        !          2039: 
        !          2040:        slash = memchr(pos, '/', filename_len - (pos - filename));
        !          2041: 
        !          2042:        if (!slash) {
        !          2043:                /* this is a url like "phar://blah.phar" with no directory */
        !          2044:                *ext_str = pos;
        !          2045:                *ext_len = strlen(pos);
        !          2046: 
        !          2047:                /* file extension must contain "phar" */
        !          2048:                switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
        !          2049:                        case SUCCESS:
        !          2050:                                return SUCCESS;
        !          2051:                        case FAILURE:
        !          2052:                                /* we are at the end of the string, so we fail */
        !          2053:                                return FAILURE;
        !          2054:                }
        !          2055:        }
        !          2056: 
        !          2057:        /* we've found an extension that ends at a directory separator */
        !          2058:        *ext_str = pos;
        !          2059:        *ext_len = slash - pos;
        !          2060: 
        !          2061:        switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
        !          2062:                case SUCCESS:
        !          2063:                        return SUCCESS;
        !          2064:                case FAILURE:
        !          2065:                        /* look for more extensions */
        !          2066:                        pos = strchr(pos + 1, '.');
        !          2067:                        if (pos) {
        !          2068:                                *ext_str = NULL;
        !          2069:                                *ext_len = 0;
        !          2070:                        }
        !          2071:                        goto next_extension;
        !          2072:        }
        !          2073: 
        !          2074:        return FAILURE;
        !          2075: }
        !          2076: /* }}} */
        !          2077: 
        !          2078: static int php_check_dots(const char *element, int n) /* {{{ */
        !          2079: {
        !          2080:        for(n--; n >= 0; --n) {
        !          2081:                if (element[n] != '.') {
        !          2082:                        return 1;
        !          2083:                }
        !          2084:        }
        !          2085:        return 0;
        !          2086: }
        !          2087: /* }}} */
        !          2088: 
        !          2089: #define IS_DIRECTORY_UP(element, len) \
        !          2090:        (len >= 2 && !php_check_dots(element, len))
        !          2091: 
        !          2092: #define IS_DIRECTORY_CURRENT(element, len) \
        !          2093:        (len == 1 && element[0] == '.')
        !          2094: 
        !          2095: #define IS_BACKSLASH(c) ((c) == '/')
        !          2096: 
        !          2097: #ifdef COMPILE_DL_PHAR
        !          2098: /* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */
        !          2099: static inline int in_character_class(char ch, const char *delim) /* {{{ */
        !          2100: {
        !          2101:        while (*delim) {
        !          2102:                if (*delim == ch) {
        !          2103:                        return 1;
        !          2104:                }
        !          2105:                ++delim;
        !          2106:        }
        !          2107:        return 0;
        !          2108: }
        !          2109: /* }}} */
        !          2110: 
        !          2111: char *tsrm_strtok_r(char *s, const char *delim, char **last) /* {{{ */
        !          2112: {
        !          2113:        char *token;
        !          2114: 
        !          2115:        if (s == NULL) {
        !          2116:                s = *last;
        !          2117:        }
        !          2118: 
        !          2119:        while (*s && in_character_class(*s, delim)) {
        !          2120:                ++s;
        !          2121:        }
        !          2122: 
        !          2123:        if (!*s) {
        !          2124:                return NULL;
        !          2125:        }
        !          2126: 
        !          2127:        token = s;
        !          2128: 
        !          2129:        while (*s && !in_character_class(*s, delim)) {
        !          2130:                ++s;
        !          2131:        }
        !          2132: 
        !          2133:        if (!*s) {
        !          2134:                *last = s;
        !          2135:        } else {
        !          2136:                *s = '\0';
        !          2137:                *last = s + 1;
        !          2138:        }
        !          2139: 
        !          2140:        return token;
        !          2141: }
        !          2142: /* }}} */
        !          2143: #endif
        !          2144: 
        !          2145: /**
        !          2146:  * Remove .. and . references within a phar filename
        !          2147:  */
        !          2148: char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
        !          2149: {
        !          2150:        char newpath[MAXPATHLEN];
        !          2151:        int newpath_len;
        !          2152:        char *ptr;
        !          2153:        char *tok;
        !          2154:        int ptr_length, path_length = *new_len;
        !          2155: 
        !          2156:        if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
        !          2157:                newpath_len = PHAR_G(cwd_len);
        !          2158:                memcpy(newpath, PHAR_G(cwd), newpath_len);
        !          2159:        } else {
        !          2160:                newpath[0] = '/';
        !          2161:                newpath_len = 1;
        !          2162:        }
        !          2163: 
        !          2164:        ptr = path;
        !          2165: 
        !          2166:        if (*ptr == '/') {
        !          2167:                ++ptr;
        !          2168:        }
        !          2169: 
        !          2170:        tok = ptr;
        !          2171: 
        !          2172:        do {
        !          2173:                ptr = memchr(ptr, '/', path_length - (ptr - path));
        !          2174:        } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
        !          2175: 
        !          2176:        if (!ptr && (path_length - (tok - path))) {
        !          2177:                switch (path_length - (tok - path)) {
        !          2178:                        case 1:
        !          2179:                                if (*tok == '.') {
        !          2180:                                        efree(path);
        !          2181:                                        *new_len = 1;
        !          2182:                                        return estrndup("/", 1);
        !          2183:                                }
        !          2184:                                break;
        !          2185:                        case 2:
        !          2186:                                if (tok[0] == '.' && tok[1] == '.') {
        !          2187:                                        efree(path);
        !          2188:                                        *new_len = 1;
        !          2189:                                        return estrndup("/", 1);
        !          2190:                                }
        !          2191:                }
        !          2192:                return path;
        !          2193:        }
        !          2194: 
        !          2195:        while (ptr) {
        !          2196:                ptr_length = ptr - tok;
        !          2197: last_time:
        !          2198:                if (IS_DIRECTORY_UP(tok, ptr_length)) {
        !          2199: #define PREVIOUS newpath[newpath_len - 1]
        !          2200: 
        !          2201:                        while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
        !          2202:                                newpath_len--;
        !          2203:                        }
        !          2204: 
        !          2205:                        if (newpath[0] != '/') {
        !          2206:                                newpath[newpath_len] = '\0';
        !          2207:                        } else if (newpath_len > 1) {
        !          2208:                                --newpath_len;
        !          2209:                        }
        !          2210:                } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
        !          2211:                        if (newpath_len > 1) {
        !          2212:                                newpath[newpath_len++] = '/';
        !          2213:                                memcpy(newpath + newpath_len, tok, ptr_length+1);
        !          2214:                        } else {
        !          2215:                                memcpy(newpath + newpath_len, tok, ptr_length+1);
        !          2216:                        }
        !          2217: 
        !          2218:                        newpath_len += ptr_length;
        !          2219:                }
        !          2220: 
        !          2221:                if (ptr == path + path_length) {
        !          2222:                        break;
        !          2223:                }
        !          2224: 
        !          2225:                tok = ++ptr;
        !          2226: 
        !          2227:                do {
        !          2228:                        ptr = memchr(ptr, '/', path_length - (ptr - path));
        !          2229:                } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
        !          2230: 
        !          2231:                if (!ptr && (path_length - (tok - path))) {
        !          2232:                        ptr_length = path_length - (tok - path);
        !          2233:                        ptr = path + path_length;
        !          2234:                        goto last_time;
        !          2235:                }
        !          2236:        }
        !          2237: 
        !          2238:        efree(path);
        !          2239:        *new_len = newpath_len;
        !          2240:        return estrndup(newpath, newpath_len);
        !          2241: }
        !          2242: /* }}} */
        !          2243: 
        !          2244: /**
        !          2245:  * Process a phar stream name, ensuring we can handle any of:
        !          2246:  * 
        !          2247:  * - whatever.phar
        !          2248:  * - whatever.phar.gz
        !          2249:  * - whatever.phar.bz2
        !          2250:  * - whatever.phar.php
        !          2251:  *
        !          2252:  * Optionally the name might start with 'phar://'
        !          2253:  *
        !          2254:  * This is used by phar_parse_url()
        !          2255:  */
        !          2256: int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
        !          2257: {
        !          2258:        const char *ext_str;
        !          2259: #ifdef PHP_WIN32
        !          2260:        char *save;
        !          2261: #endif
        !          2262:        int ext_len, free_filename = 0;
        !          2263: 
        !          2264:        if (!strncasecmp(filename, "phar://", 7)) {
        !          2265:                filename += 7;
        !          2266:                filename_len -= 7;
        !          2267:        }
        !          2268: 
        !          2269:        ext_len = 0;
        !          2270: #ifdef PHP_WIN32
        !          2271:        free_filename = 1;
        !          2272:        save = filename;
        !          2273:        filename = estrndup(filename, filename_len);
        !          2274:        phar_unixify_path_separators(filename, filename_len);
        !          2275: #endif
        !          2276:        if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
        !          2277:                if (ext_len != -1) {
        !          2278:                        if (!ext_str) {
        !          2279:                                /* no / detected, restore arch for error message */
        !          2280: #ifdef PHP_WIN32
        !          2281:                                *arch = save;
        !          2282: #else
        !          2283:                                *arch = filename;
        !          2284: #endif
        !          2285:                        }
        !          2286: 
        !          2287:                        if (free_filename) {
        !          2288:                                efree(filename);
        !          2289:                        }
        !          2290: 
        !          2291:                        return FAILURE;
        !          2292:                }
        !          2293: 
        !          2294:                ext_len = 0;
        !          2295:                /* no extension detected - instead we are dealing with an alias */
        !          2296:        }
        !          2297: 
        !          2298:        *arch_len = ext_str - filename + ext_len;
        !          2299:        *arch = estrndup(filename, *arch_len);
        !          2300: 
        !          2301:        if (ext_str[ext_len]) {
        !          2302:                *entry_len = filename_len - *arch_len;
        !          2303:                *entry = estrndup(ext_str+ext_len, *entry_len);
        !          2304: #ifdef PHP_WIN32
        !          2305:                phar_unixify_path_separators(*entry, *entry_len);
        !          2306: #endif
        !          2307:                *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
        !          2308:        } else {
        !          2309:                *entry_len = 1;
        !          2310:                *entry = estrndup("/", 1);
        !          2311:        }
        !          2312: 
        !          2313:        if (free_filename) {
        !          2314:                efree(filename);
        !          2315:        }
        !          2316: 
        !          2317:        return SUCCESS;
        !          2318: }
        !          2319: /* }}} */
        !          2320: 
        !          2321: /**
        !          2322:  * Invoked when a user calls Phar::mapPhar() from within an executing .phar
        !          2323:  * to set up its manifest directly
        !          2324:  */
        !          2325: int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
        !          2326: {
        !          2327:        char *fname;
        !          2328:        zval *halt_constant;
        !          2329:        php_stream *fp;
        !          2330:        int fname_len;
        !          2331:        char *actual = NULL;
        !          2332:        int ret;
        !          2333: 
        !          2334:        if (error) {
        !          2335:                *error = NULL;
        !          2336:        }
        !          2337: 
        !          2338:        fname = zend_get_executed_filename(TSRMLS_C);
        !          2339:        fname_len = strlen(fname);
        !          2340: 
        !          2341:        if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
        !          2342:                return SUCCESS;
        !          2343:        }
        !          2344: 
        !          2345:        if (!strcmp(fname, "[no active file]")) {
        !          2346:                if (error) {
        !          2347:                        spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
        !          2348:                }
        !          2349:                return FAILURE;
        !          2350:        }
        !          2351: 
        !          2352:        MAKE_STD_ZVAL(halt_constant);
        !          2353: 
        !          2354:        if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
        !          2355:                FREE_ZVAL(halt_constant);
        !          2356:                if (error) {
        !          2357:                        spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
        !          2358:                }
        !          2359:                return FAILURE;
        !          2360:        }
        !          2361: 
        !          2362:        FREE_ZVAL(halt_constant);
        !          2363: 
        !          2364: #if PHP_API_VERSION < 20100412
        !          2365:        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
        !          2366:                return FAILURE;
        !          2367:        }
        !          2368: #endif
        !          2369: 
        !          2370:        if (php_check_open_basedir(fname TSRMLS_CC)) {
        !          2371:                return FAILURE;
        !          2372:        }
        !          2373: 
        !          2374:        fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
        !          2375: 
        !          2376:        if (!fp) {
        !          2377:                if (error) {
        !          2378:                        spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
        !          2379:                }
        !          2380:                if (actual) {
        !          2381:                        efree(actual);
        !          2382:                }
        !          2383:                return FAILURE;
        !          2384:        }
        !          2385: 
        !          2386:        if (actual) {
        !          2387:                fname = actual;
        !          2388:                fname_len = strlen(actual);
        !          2389:        }
        !          2390: 
        !          2391:        ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error TSRMLS_CC);
        !          2392: 
        !          2393:        if (actual) {
        !          2394:                efree(actual);
        !          2395:        }
        !          2396: 
        !          2397:        return ret;
        !          2398: }
        !          2399: /* }}} */
        !          2400: 
        !          2401: /**
        !          2402:  * Validate the CRC32 of a file opened from within the phar
        !          2403:  */
        !          2404: int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
        !          2405: {
        !          2406:        php_uint32 crc = ~0;
        !          2407:        int len = idata->internal_file->uncompressed_filesize;
        !          2408:        php_stream *fp = idata->fp;
        !          2409:        phar_entry_info *entry = idata->internal_file;
        !          2410: 
        !          2411:        if (error) {
        !          2412:                *error = NULL;
        !          2413:        }
        !          2414: 
        !          2415:        if (entry->is_zip && process_zip > 0) {
        !          2416:                /* verify local file header */
        !          2417:                phar_zip_file_header local;
        !          2418:                phar_zip_data_desc desc;
        !          2419: 
        !          2420:                if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
        !          2421:                        spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
        !          2422:                        return FAILURE;
        !          2423:                }
        !          2424:                php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
        !          2425: 
        !          2426:                if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
        !          2427: 
        !          2428:                        spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
        !          2429:                        return FAILURE;
        !          2430:                }
        !          2431: 
        !          2432:                /* check for data descriptor */
        !          2433:                if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
        !          2434:                        php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
        !          2435:                                        entry->header_offset + sizeof(local) +
        !          2436:                                        PHAR_ZIP_16(local.filename_len) +
        !          2437:                                        PHAR_ZIP_16(local.extra_len) +
        !          2438:                                        entry->compressed_filesize, SEEK_SET);
        !          2439:                        if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
        !          2440:                                                            (char *) &desc, sizeof(desc))) {
        !          2441:                                spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, entry->filename);
        !          2442:                                return FAILURE;
        !          2443:                        }
        !          2444:                        if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
        !          2445:                                memcpy(&(local.crc32), &(desc.crc32), 12);
        !          2446:                        } else {
        !          2447:                                /* old data descriptors have no signature */
        !          2448:                                memcpy(&(local.crc32), &desc, 12);
        !          2449:                        }
        !          2450:                }
        !          2451:                /* verify local header */
        !          2452:                if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
        !          2453:                        spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
        !          2454:                        return FAILURE;
        !          2455:                }
        !          2456: 
        !          2457:                /* construct actual offset to file start - local extra_len can be different from central extra_len */
        !          2458:                entry->offset = entry->offset_abs =
        !          2459:                        sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
        !          2460: 
        !          2461:                if (idata->zero && idata->zero != entry->offset_abs) {
        !          2462:                        idata->zero = entry->offset_abs;
        !          2463:                }
        !          2464:        }
        !          2465: 
        !          2466:        if (process_zip == 1) {
        !          2467:                return SUCCESS;
        !          2468:        }
        !          2469: 
        !          2470:        php_stream_seek(fp, idata->zero, SEEK_SET);
        !          2471: 
        !          2472:        while (len--) {
        !          2473:                CRC32(crc, php_stream_getc(fp));
        !          2474:        }
        !          2475: 
        !          2476:        php_stream_seek(fp, idata->zero, SEEK_SET);
        !          2477: 
        !          2478:        if (~crc == crc32) {
        !          2479:                entry->is_crc_checked = 1;
        !          2480:                return SUCCESS;
        !          2481:        } else {
        !          2482:                spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
        !          2483:                return FAILURE;
        !          2484:        }
        !          2485: }
        !          2486: /* }}} */
        !          2487: 
        !          2488: static inline void phar_set_32(char *buffer, int var) /* {{{ */
        !          2489: {
        !          2490: #ifdef WORDS_BIGENDIAN
        !          2491:        *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
        !          2492:        *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
        !          2493:        *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
        !          2494:        *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
        !          2495: #else
        !          2496:         memcpy(buffer, &var, sizeof(var));
        !          2497: #endif
        !          2498: } /* }}} */
        !          2499: 
        !          2500: static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */
        !          2501: {
        !          2502:        phar_entry_info *entry = (phar_entry_info *)data;
        !          2503: 
        !          2504:        if (entry->fp_refcount <= 0 && entry->is_deleted) {
        !          2505:                return ZEND_HASH_APPLY_REMOVE;
        !          2506:        } else {
        !          2507:                return ZEND_HASH_APPLY_KEEP;
        !          2508:        }
        !          2509: }
        !          2510: /* }}} */
        !          2511: 
        !          2512: #include "stub.h"
        !          2513: 
        !          2514: char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) /* {{{ */
        !          2515: {
        !          2516:        char *stub = NULL;
        !          2517:        int index_len, web_len;
        !          2518:        size_t dummy;
        !          2519: 
        !          2520:        if (!len) {
        !          2521:                len = &dummy;
        !          2522:        }
        !          2523: 
        !          2524:        if (error) {
        !          2525:                *error = NULL;
        !          2526:        }
        !          2527: 
        !          2528:        if (!index_php) {
        !          2529:                index_php = "index.php";
        !          2530:        }
        !          2531: 
        !          2532:        if (!web_index) {
        !          2533:                web_index = "index.php";
        !          2534:        }
        !          2535: 
        !          2536:        index_len = strlen(index_php);
        !          2537:        web_len = strlen(web_index);
        !          2538: 
        !          2539:        if (index_len > 400) {
        !          2540:                /* ridiculous size not allowed for index.php startup filename */
        !          2541:                if (error) {
        !          2542:                        spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
        !          2543:                        return NULL;
        !          2544:                }
        !          2545:        }
        !          2546: 
        !          2547:        if (web_len > 400) {
        !          2548:                /* ridiculous size not allowed for index.php startup filename */
        !          2549:                if (error) {
        !          2550:                        spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
        !          2551:                        return NULL;
        !          2552:                }
        !          2553:        }
        !          2554: 
        !          2555:        phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
        !          2556:        return stub;
        !          2557: }
        !          2558: /* }}} */
        !          2559: 
        !          2560: /**
        !          2561:  * Save phar contents to disk
        !          2562:  *
        !          2563:  * user_stub contains either a string, or a resource pointer, if len is a negative length.
        !          2564:  * user_stub and len should be both 0 if the default or existing stub should be used
        !          2565:  */
        !          2566: int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC) /* {{{ */
        !          2567: {
        !          2568:        char halt_stub[] = "__HALT_COMPILER();";
        !          2569:        char *newstub, *tmp;
        !          2570:        phar_entry_info *entry, *newentry;
        !          2571:        int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
        !          2572:        char *pos, has_dirs = 0;
        !          2573:        char manifest[18], entry_buffer[24];
        !          2574:        off_t manifest_ftell;
        !          2575:        long offset;
        !          2576:        size_t wrote;
        !          2577:        php_uint32 manifest_len, mytime, loc, new_manifest_count;
        !          2578:        php_uint32 newcrc32;
        !          2579:        php_stream *file, *oldfile, *newfile, *stubfile;
        !          2580:        php_stream_filter *filter;
        !          2581:        php_serialize_data_t metadata_hash;
        !          2582:        smart_str main_metadata_str = {0};
        !          2583:        int free_user_stub, free_fp = 1, free_ufp = 1;
        !          2584: 
        !          2585:        if (phar->is_persistent) {
        !          2586:                if (error) {
        !          2587:                        spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
        !          2588:                }
        !          2589:                return EOF;
        !          2590:        }
        !          2591: 
        !          2592:        if (error) {
        !          2593:                *error = NULL;
        !          2594:        }
        !          2595: 
        !          2596:        if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
        !          2597:                return EOF;
        !          2598:        }
        !          2599: 
        !          2600:        zend_hash_clean(&phar->virtual_dirs);
        !          2601: 
        !          2602:        if (phar->is_zip) {
        !          2603:                return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
        !          2604:        }
        !          2605: 
        !          2606:        if (phar->is_tar) {
        !          2607:                return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
        !          2608:        }
        !          2609: 
        !          2610:        if (PHAR_G(readonly)) {
        !          2611:                return EOF;
        !          2612:        }
        !          2613: 
        !          2614:        if (phar->fp && !phar->is_brandnew) {
        !          2615:                oldfile = phar->fp;
        !          2616:                closeoldfile = 0;
        !          2617:                php_stream_rewind(oldfile);
        !          2618:        } else {
        !          2619:                oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
        !          2620:                closeoldfile = oldfile != NULL;
        !          2621:        }
        !          2622:        newfile = php_stream_fopen_tmpfile();
        !          2623:        if (!newfile) {
        !          2624:                if (error) {
        !          2625:                        spprintf(error, 0, "unable to create temporary file");
        !          2626:                }
        !          2627:                if (closeoldfile) {
        !          2628:                        php_stream_close(oldfile);
        !          2629:                }
        !          2630:                return EOF;
        !          2631:        }
        !          2632: 
        !          2633:        if (user_stub) {
        !          2634:                if (len < 0) {
        !          2635:                        /* resource passed in */
        !          2636:                        if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
        !          2637:                                if (closeoldfile) {
        !          2638:                                        php_stream_close(oldfile);
        !          2639:                                }
        !          2640:                                php_stream_close(newfile);
        !          2641:                                if (error) {
        !          2642:                                        spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
        !          2643:                                }
        !          2644:                                return EOF;
        !          2645:                        }
        !          2646:                        if (len == -1) {
        !          2647:                                len = PHP_STREAM_COPY_ALL;
        !          2648:                        } else {
        !          2649:                                len = -len;
        !          2650:                        }
        !          2651:                        user_stub = 0;
        !          2652: #if PHP_MAJOR_VERSION >= 6
        !          2653:                        if (!(len = php_stream_copy_to_mem(stubfile, (void **) &user_stub, len, 0)) || !user_stub) {
        !          2654: #else
        !          2655:                        if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
        !          2656: #endif
        !          2657:                                if (closeoldfile) {
        !          2658:                                        php_stream_close(oldfile);
        !          2659:                                }
        !          2660:                                php_stream_close(newfile);
        !          2661:                                if (error) {
        !          2662:                                        spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
        !          2663:                                }
        !          2664:                                return EOF;
        !          2665:                        }
        !          2666:                        free_user_stub = 1;
        !          2667:                } else {
        !          2668:                        free_user_stub = 0;
        !          2669:                }
        !          2670:                tmp = estrndup(user_stub, len);
        !          2671:                if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
        !          2672:                        efree(tmp);
        !          2673:                        if (closeoldfile) {
        !          2674:                                php_stream_close(oldfile);
        !          2675:                        }
        !          2676:                        php_stream_close(newfile);
        !          2677:                        if (error) {
        !          2678:                                spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
        !          2679:                        }
        !          2680:                        if (free_user_stub) {
        !          2681:                                efree(user_stub);
        !          2682:                        }
        !          2683:                        return EOF;
        !          2684:                }
        !          2685:                pos = user_stub + (pos - tmp);
        !          2686:                efree(tmp);
        !          2687:                len = pos - user_stub + 18;
        !          2688:                if ((size_t)len != php_stream_write(newfile, user_stub, len)
        !          2689:                ||                        5 != php_stream_write(newfile, " ?>\r\n", 5)) {
        !          2690:                        if (closeoldfile) {
        !          2691:                                php_stream_close(oldfile);
        !          2692:                        }
        !          2693:                        php_stream_close(newfile);
        !          2694:                        if (error) {
        !          2695:                                spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
        !          2696:                        }
        !          2697:                        if (free_user_stub) {
        !          2698:                                efree(user_stub);
        !          2699:                        }
        !          2700:                        return EOF;
        !          2701:                }
        !          2702:                phar->halt_offset = len + 5;
        !          2703:                if (free_user_stub) {
        !          2704:                        efree(user_stub);
        !          2705:                }
        !          2706:        } else {
        !          2707:                size_t written;
        !          2708: 
        !          2709:                if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
        !          2710:                        phar_stream_copy_to_stream(oldfile, newfile, phar->halt_offset, &written);
        !          2711:                        newstub = NULL;
        !          2712:                } else {
        !          2713:                        /* this is either a brand new phar or a default stub overwrite */
        !          2714:                        newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
        !          2715:                        written = php_stream_write(newfile, newstub, phar->halt_offset);
        !          2716:                }
        !          2717:                if (phar->halt_offset != written) {
        !          2718:                        if (closeoldfile) {
        !          2719:                                php_stream_close(oldfile);
        !          2720:                        }
        !          2721:                        php_stream_close(newfile);
        !          2722:                        if (error) {
        !          2723:                                if (newstub) {
        !          2724:                                        spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
        !          2725:                                } else {
        !          2726:                                        spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
        !          2727:                                }
        !          2728:                        }
        !          2729:                        if (newstub) {
        !          2730:                                efree(newstub);
        !          2731:                        }
        !          2732:                        return EOF;
        !          2733:                }
        !          2734:                if (newstub) {
        !          2735:                        efree(newstub);
        !          2736:                }
        !          2737:        }
        !          2738:        manifest_ftell = php_stream_tell(newfile);
        !          2739:        halt_offset = manifest_ftell;
        !          2740: 
        !          2741:        /* Check whether we can get rid of some of the deleted entries which are
        !          2742:         * unused. However some might still be in use so even after this clean-up
        !          2743:         * we need to skip entries marked is_deleted. */
        !          2744:        zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
        !          2745: 
        !          2746:        /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
        !          2747:        main_metadata_str.c = 0;
        !          2748:        if (phar->metadata) {
        !          2749:                PHP_VAR_SERIALIZE_INIT(metadata_hash);
        !          2750:                php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
        !          2751:                PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
        !          2752:        } else {
        !          2753:                main_metadata_str.len = 0;
        !          2754:        }
        !          2755:        new_manifest_count = 0;
        !          2756:        offset = 0;
        !          2757:        for (zend_hash_internal_pointer_reset(&phar->manifest);
        !          2758:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
        !          2759:                zend_hash_move_forward(&phar->manifest)) {
        !          2760:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
        !          2761:                        continue;
        !          2762:                }
        !          2763:                if (entry->cfp) {
        !          2764:                        /* did we forget to get rid of cfp last time? */
        !          2765:                        php_stream_close(entry->cfp);
        !          2766:                        entry->cfp = 0;
        !          2767:                }
        !          2768:                if (entry->is_deleted || entry->is_mounted) {
        !          2769:                        /* remove this from the new phar */
        !          2770:                        continue;
        !          2771:                }
        !          2772:                if (!entry->is_modified && entry->fp_refcount) {
        !          2773:                        /* open file pointers refer to this fp, do not free the stream */
        !          2774:                        switch (entry->fp_type) {
        !          2775:                                case PHAR_FP:
        !          2776:                                        free_fp = 0;
        !          2777:                                        break;
        !          2778:                                case PHAR_UFP:
        !          2779:                                        free_ufp = 0;
        !          2780:                                default:
        !          2781:                                        break;
        !          2782:                        }
        !          2783:                }
        !          2784:                /* after excluding deleted files, calculate manifest size in bytes and number of entries */
        !          2785:                ++new_manifest_count;
        !          2786:                phar_add_virtual_dirs(phar, entry->filename, entry->filename_len TSRMLS_CC);
        !          2787: 
        !          2788:                if (entry->is_dir) {
        !          2789:                        /* we use this to calculate API version, 1.1.1 is used for phars with directories */
        !          2790:                        has_dirs = 1;
        !          2791:                }
        !          2792:                if (entry->metadata) {
        !          2793:                        if (entry->metadata_str.c) {
        !          2794:                                smart_str_free(&entry->metadata_str);
        !          2795:                        }
        !          2796:                        entry->metadata_str.c = 0;
        !          2797:                        entry->metadata_str.len = 0;
        !          2798:                        PHP_VAR_SERIALIZE_INIT(metadata_hash);
        !          2799:                        php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
        !          2800:                        PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
        !          2801:                } else {
        !          2802:                        if (entry->metadata_str.c) {
        !          2803:                                smart_str_free(&entry->metadata_str);
        !          2804:                        }
        !          2805:                        entry->metadata_str.c = 0;
        !          2806:                        entry->metadata_str.len = 0;
        !          2807:                }
        !          2808: 
        !          2809:                /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
        !          2810:                offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
        !          2811: 
        !          2812:                /* compress and rehash as necessary */
        !          2813:                if ((oldfile && !entry->is_modified) || entry->is_dir) {
        !          2814:                        if (entry->fp_type == PHAR_UFP) {
        !          2815:                                /* reset so we can copy the compressed data over */
        !          2816:                                entry->fp_type = PHAR_FP;
        !          2817:                        }
        !          2818:                        continue;
        !          2819:                }
        !          2820:                if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
        !          2821:                        /* re-open internal file pointer just-in-time */
        !          2822:                        newentry = phar_open_jit(phar, entry, error TSRMLS_CC);
        !          2823:                        if (!newentry) {
        !          2824:                                /* major problem re-opening, so we ignore this file and the error */
        !          2825:                                efree(*error);
        !          2826:                                *error = NULL;
        !          2827:                                continue;
        !          2828:                        }
        !          2829:                        entry = newentry;
        !          2830:                }
        !          2831:                file = phar_get_efp(entry, 0 TSRMLS_CC);
        !          2832:                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
        !          2833:                        if (closeoldfile) {
        !          2834:                                php_stream_close(oldfile);
        !          2835:                        }
        !          2836:                        php_stream_close(newfile);
        !          2837:                        if (error) {
        !          2838:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
        !          2839:                        }
        !          2840:                        return EOF;
        !          2841:                }
        !          2842:                newcrc32 = ~0;
        !          2843:                mytime = entry->uncompressed_filesize;
        !          2844:                for (loc = 0;loc < mytime; ++loc) {
        !          2845:                        CRC32(newcrc32, php_stream_getc(file));
        !          2846:                }
        !          2847:                entry->crc32 = ~newcrc32;
        !          2848:                entry->is_crc_checked = 1;
        !          2849:                if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
        !          2850:                        /* not compressed */
        !          2851:                        entry->compressed_filesize = entry->uncompressed_filesize;
        !          2852:                        continue;
        !          2853:                }
        !          2854:                filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
        !          2855:                if (!filter) {
        !          2856:                        if (closeoldfile) {
        !          2857:                                php_stream_close(oldfile);
        !          2858:                        }
        !          2859:                        php_stream_close(newfile);
        !          2860:                        if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
        !          2861:                                if (error) {
        !          2862:                                        spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
        !          2863:                                }
        !          2864:                        } else {
        !          2865:                                if (error) {
        !          2866:                                        spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
        !          2867:                                }
        !          2868:                        }
        !          2869:                        return EOF;
        !          2870:                }
        !          2871: 
        !          2872:                /* create new file that holds the compressed version */
        !          2873:                /* work around inability to specify freedom in write and strictness
        !          2874:                in read count */
        !          2875:                entry->cfp = php_stream_fopen_tmpfile();
        !          2876:                if (!entry->cfp) {
        !          2877:                        if (error) {
        !          2878:                                spprintf(error, 0, "unable to create temporary file");
        !          2879:                        }
        !          2880:                        if (closeoldfile) {
        !          2881:                                php_stream_close(oldfile);
        !          2882:                        }
        !          2883:                        php_stream_close(newfile);
        !          2884:                        return EOF;
        !          2885:                }
        !          2886:                php_stream_flush(file);
        !          2887:                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
        !          2888:                        if (closeoldfile) {
        !          2889:                                php_stream_close(oldfile);
        !          2890:                        }
        !          2891:                        php_stream_close(newfile);
        !          2892:                        if (error) {
        !          2893:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
        !          2894:                        }
        !          2895:                        return EOF;
        !          2896:                }
        !          2897:                php_stream_filter_append((&entry->cfp->writefilters), filter);
        !          2898:                if (SUCCESS != phar_stream_copy_to_stream(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
        !          2899:                        if (closeoldfile) {
        !          2900:                                php_stream_close(oldfile);
        !          2901:                        }
        !          2902:                        php_stream_close(newfile);
        !          2903:                        if (error) {
        !          2904:                                spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
        !          2905:                        }
        !          2906:                        return EOF;
        !          2907:                }
        !          2908:                php_stream_filter_flush(filter, 1);
        !          2909:                php_stream_flush(entry->cfp);
        !          2910:                php_stream_filter_remove(filter, 1 TSRMLS_CC);
        !          2911:                php_stream_seek(entry->cfp, 0, SEEK_END);
        !          2912:                entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
        !          2913:                /* generate crc on compressed file */
        !          2914:                php_stream_rewind(entry->cfp);
        !          2915:                entry->old_flags = entry->flags;
        !          2916:                entry->is_modified = 1;
        !          2917:                global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
        !          2918:        }
        !          2919:        global_flags |= PHAR_HDR_SIGNATURE;
        !          2920: 
        !          2921:        /* write out manifest pre-header */
        !          2922:        /*  4: manifest length
        !          2923:         *  4: manifest entry count
        !          2924:         *  2: phar version
        !          2925:         *  4: phar global flags
        !          2926:         *  4: alias length
        !          2927:         *  ?: the alias itself
        !          2928:         *  4: phar metadata length
        !          2929:         *  ?: phar metadata
        !          2930:         */
        !          2931:        restore_alias_len = phar->alias_len;
        !          2932:        if (phar->is_temporary_alias) {
        !          2933:                phar->alias_len = 0;
        !          2934:        }
        !          2935: 
        !          2936:        manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
        !          2937:        phar_set_32(manifest, manifest_len);
        !          2938:        phar_set_32(manifest+4, new_manifest_count);
        !          2939:        if (has_dirs) {
        !          2940:                *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
        !          2941:                *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
        !          2942:        } else {
        !          2943:                *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
        !          2944:                *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
        !          2945:        }
        !          2946:        phar_set_32(manifest+10, global_flags);
        !          2947:        phar_set_32(manifest+14, phar->alias_len);
        !          2948: 
        !          2949:        /* write the manifest header */
        !          2950:        if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
        !          2951:        || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
        !          2952: 
        !          2953:                if (closeoldfile) {
        !          2954:                        php_stream_close(oldfile);
        !          2955:                }
        !          2956: 
        !          2957:                php_stream_close(newfile);
        !          2958:                phar->alias_len = restore_alias_len;
        !          2959: 
        !          2960:                if (error) {
        !          2961:                        spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
        !          2962:                }
        !          2963: 
        !          2964:                return EOF;
        !          2965:        }
        !          2966: 
        !          2967:        phar->alias_len = restore_alias_len;
        !          2968: 
        !          2969:        phar_set_32(manifest, main_metadata_str.len);
        !          2970:        if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
        !          2971:        && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
        !          2972:                smart_str_free(&main_metadata_str);
        !          2973: 
        !          2974:                if (closeoldfile) {
        !          2975:                        php_stream_close(oldfile);
        !          2976:                }
        !          2977: 
        !          2978:                php_stream_close(newfile);
        !          2979:                phar->alias_len = restore_alias_len;
        !          2980: 
        !          2981:                if (error) {
        !          2982:                        spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
        !          2983:                }
        !          2984: 
        !          2985:                return EOF;
        !          2986:        }
        !          2987:        smart_str_free(&main_metadata_str);
        !          2988: 
        !          2989:        /* re-calculate the manifest location to simplify later code */
        !          2990:        manifest_ftell = php_stream_tell(newfile);
        !          2991: 
        !          2992:        /* now write the manifest */
        !          2993:        for (zend_hash_internal_pointer_reset(&phar->manifest);
        !          2994:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
        !          2995:                zend_hash_move_forward(&phar->manifest)) {
        !          2996: 
        !          2997:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
        !          2998:                        continue;
        !          2999:                }
        !          3000: 
        !          3001:                if (entry->is_deleted || entry->is_mounted) {
        !          3002:                        /* remove this from the new phar if deleted, ignore if mounted */
        !          3003:                        continue;
        !          3004:                }
        !          3005: 
        !          3006:                if (entry->is_dir) {
        !          3007:                        /* add 1 for trailing slash */
        !          3008:                        phar_set_32(entry_buffer, entry->filename_len + 1);
        !          3009:                } else {
        !          3010:                        phar_set_32(entry_buffer, entry->filename_len);
        !          3011:                }
        !          3012: 
        !          3013:                if (4 != php_stream_write(newfile, entry_buffer, 4)
        !          3014:                || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
        !          3015:                || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
        !          3016:                        if (closeoldfile) {
        !          3017:                                php_stream_close(oldfile);
        !          3018:                        }
        !          3019:                        php_stream_close(newfile);
        !          3020:                        if (error) {
        !          3021:                                if (entry->is_dir) {
        !          3022:                                        spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
        !          3023:                                } else {
        !          3024:                                        spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
        !          3025:                                }
        !          3026:                        }
        !          3027:                        return EOF;
        !          3028:                }
        !          3029: 
        !          3030:                /* set the manifest meta-data:
        !          3031:                        4: uncompressed filesize
        !          3032:                        4: creation timestamp
        !          3033:                        4: compressed filesize
        !          3034:                        4: crc32
        !          3035:                        4: flags
        !          3036:                        4: metadata-len
        !          3037:                        +: metadata
        !          3038:                */
        !          3039:                mytime = time(NULL);
        !          3040:                phar_set_32(entry_buffer, entry->uncompressed_filesize);
        !          3041:                phar_set_32(entry_buffer+4, mytime);
        !          3042:                phar_set_32(entry_buffer+8, entry->compressed_filesize);
        !          3043:                phar_set_32(entry_buffer+12, entry->crc32);
        !          3044:                phar_set_32(entry_buffer+16, entry->flags);
        !          3045:                phar_set_32(entry_buffer+20, entry->metadata_str.len);
        !          3046: 
        !          3047:                if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
        !          3048:                || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
        !          3049:                        if (closeoldfile) {
        !          3050:                                php_stream_close(oldfile);
        !          3051:                        }
        !          3052: 
        !          3053:                        php_stream_close(newfile);
        !          3054: 
        !          3055:                        if (error) {
        !          3056:                                spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
        !          3057:                        }
        !          3058: 
        !          3059:                        return EOF;
        !          3060:                }
        !          3061:        }
        !          3062: 
        !          3063:        /* now copy the actual file data to the new phar */
        !          3064:        offset = php_stream_tell(newfile);
        !          3065:        for (zend_hash_internal_pointer_reset(&phar->manifest);
        !          3066:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
        !          3067:                zend_hash_move_forward(&phar->manifest)) {
        !          3068: 
        !          3069:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
        !          3070:                        continue;
        !          3071:                }
        !          3072: 
        !          3073:                if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
        !          3074:                        continue;
        !          3075:                }
        !          3076: 
        !          3077:                if (entry->cfp) {
        !          3078:                        file = entry->cfp;
        !          3079:                        php_stream_rewind(file);
        !          3080:                } else {
        !          3081:                        file = phar_get_efp(entry, 0 TSRMLS_CC);
        !          3082:                        if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
        !          3083:                                if (closeoldfile) {
        !          3084:                                        php_stream_close(oldfile);
        !          3085:                                }
        !          3086:                                php_stream_close(newfile);
        !          3087:                                if (error) {
        !          3088:                                        spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
        !          3089:                                }
        !          3090:                                return EOF;
        !          3091:                        }
        !          3092:                }
        !          3093: 
        !          3094:                if (!file) {
        !          3095:                        if (closeoldfile) {
        !          3096:                                php_stream_close(oldfile);
        !          3097:                        }
        !          3098:                        php_stream_close(newfile);
        !          3099:                        if (error) {
        !          3100:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
        !          3101:                        }
        !          3102:                        return EOF;
        !          3103:                }
        !          3104: 
        !          3105:                /* this will have changed for all files that have either changed compression or been modified */
        !          3106:                entry->offset = entry->offset_abs = offset;
        !          3107:                offset += entry->compressed_filesize;
        !          3108:                if (phar_stream_copy_to_stream(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
        !          3109:                        if (closeoldfile) {
        !          3110:                                php_stream_close(oldfile);
        !          3111:                        }
        !          3112: 
        !          3113:                        php_stream_close(newfile);
        !          3114: 
        !          3115:                        if (error) {
        !          3116:                                spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
        !          3117:                        }
        !          3118: 
        !          3119:                        return EOF;
        !          3120:                }
        !          3121: 
        !          3122:                entry->is_modified = 0;
        !          3123: 
        !          3124:                if (entry->cfp) {
        !          3125:                        php_stream_close(entry->cfp);
        !          3126:                        entry->cfp = NULL;
        !          3127:                }
        !          3128: 
        !          3129:                if (entry->fp_type == PHAR_MOD) {
        !          3130:                        /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
        !          3131:                        if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
        !          3132:                                php_stream_close(entry->fp);
        !          3133:                        }
        !          3134: 
        !          3135:                        entry->fp = NULL;
        !          3136:                        entry->fp_type = PHAR_FP;
        !          3137:                } else if (entry->fp_type == PHAR_UFP) {
        !          3138:                        entry->fp_type = PHAR_FP;
        !          3139:                }
        !          3140:        }
        !          3141: 
        !          3142:        /* append signature */
        !          3143:        if (global_flags & PHAR_HDR_SIGNATURE) {
        !          3144:                char sig_buf[4];
        !          3145: 
        !          3146:                php_stream_rewind(newfile);
        !          3147: 
        !          3148:                if (phar->signature) {
        !          3149:                        efree(phar->signature);
        !          3150:                        phar->signature = NULL;
        !          3151:                }
        !          3152: 
        !          3153:                switch(phar->sig_flags) {
        !          3154: #ifndef PHAR_HASH_OK
        !          3155:                        case PHAR_SIG_SHA512:
        !          3156:                        case PHAR_SIG_SHA256:
        !          3157:                                if (closeoldfile) {
        !          3158:                                        php_stream_close(oldfile);
        !          3159:                                }
        !          3160:                                php_stream_close(newfile);
        !          3161:                                if (error) {
        !          3162:                                        spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
        !          3163:                                }
        !          3164:                                return EOF;
        !          3165: #endif
        !          3166:                        default: {
        !          3167:                                char *digest = NULL;
        !          3168:                                int digest_len;
        !          3169: 
        !          3170:                                if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
        !          3171:                                        if (error) {
        !          3172:                                                char *save = *error;
        !          3173:                                                spprintf(error, 0, "phar error: unable to write signature: %s", save);
        !          3174:                                                efree(save);
        !          3175:                                        }
        !          3176:                                        if (digest) {
        !          3177:                                                efree(digest);
        !          3178:                                        }
        !          3179:                                        if (closeoldfile) {
        !          3180:                                                php_stream_close(oldfile);
        !          3181:                                        }
        !          3182:                                        php_stream_close(newfile);
        !          3183:                                        return EOF;
        !          3184:                                }
        !          3185: 
        !          3186:                                php_stream_write(newfile, digest, digest_len);
        !          3187:                                efree(digest);
        !          3188:                                if (phar->sig_flags == PHAR_SIG_OPENSSL) {
        !          3189:                                        phar_set_32(sig_buf, digest_len);
        !          3190:                                        php_stream_write(newfile, sig_buf, 4);
        !          3191:                                }
        !          3192:                                break;
        !          3193:                        }
        !          3194:                }
        !          3195:                phar_set_32(sig_buf, phar->sig_flags);
        !          3196:                php_stream_write(newfile, sig_buf, 4);
        !          3197:                php_stream_write(newfile, "GBMB", 4);
        !          3198:        }
        !          3199: 
        !          3200:        /* finally, close the temp file, rename the original phar,
        !          3201:           move the temp to the old phar, unlink the old phar, and reload it into memory
        !          3202:        */
        !          3203:        if (phar->fp && free_fp) {
        !          3204:                php_stream_close(phar->fp);
        !          3205:        }
        !          3206: 
        !          3207:        if (phar->ufp) {
        !          3208:                if (free_ufp) {
        !          3209:                        php_stream_close(phar->ufp);
        !          3210:                }
        !          3211:                phar->ufp = NULL;
        !          3212:        }
        !          3213: 
        !          3214:        if (closeoldfile) {
        !          3215:                php_stream_close(oldfile);
        !          3216:        }
        !          3217: 
        !          3218:        phar->internal_file_start = halt_offset + manifest_len + 4;
        !          3219:        phar->halt_offset = halt_offset;
        !          3220:        phar->is_brandnew = 0;
        !          3221: 
        !          3222:        php_stream_rewind(newfile);
        !          3223: 
        !          3224:        if (phar->donotflush) {
        !          3225:                /* deferred flush */
        !          3226:                phar->fp = newfile;
        !          3227:        } else {
        !          3228:                phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
        !          3229:                if (!phar->fp) {
        !          3230:                        phar->fp = newfile;
        !          3231:                        if (error) {
        !          3232:                                spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
        !          3233:                        }
        !          3234:                        return EOF;
        !          3235:                }
        !          3236: 
        !          3237:                if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
        !          3238:                        /* to properly compress, we have to tell zlib to add a zlib header */
        !          3239:                        zval filterparams;
        !          3240: 
        !          3241:                        array_init(&filterparams);
        !          3242:                        add_assoc_long(&filterparams, "window", MAX_WBITS+16);
        !          3243:                        filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
        !          3244:                        zval_dtor(&filterparams);
        !          3245: 
        !          3246:                        if (!filter) {
        !          3247:                                if (error) {
        !          3248:                                        spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
        !          3249:                                }
        !          3250:                                return EOF;
        !          3251:                        }
        !          3252: 
        !          3253:                        php_stream_filter_append(&phar->fp->writefilters, filter);
        !          3254:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
        !          3255:                        php_stream_filter_flush(filter, 1);
        !          3256:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
        !          3257:                        php_stream_close(phar->fp);
        !          3258:                        /* use the temp stream as our base */
        !          3259:                        phar->fp = newfile;
        !          3260:                } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
        !          3261:                        filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
        !          3262:                        php_stream_filter_append(&phar->fp->writefilters, filter);
        !          3263:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
        !          3264:                        php_stream_filter_flush(filter, 1);
        !          3265:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
        !          3266:                        php_stream_close(phar->fp);
        !          3267:                        /* use the temp stream as our base */
        !          3268:                        phar->fp = newfile;
        !          3269:                } else {
        !          3270:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
        !          3271:                        /* we could also reopen the file in "rb" mode but there is no need for that */
        !          3272:                        php_stream_close(newfile);
        !          3273:                }
        !          3274:        }
        !          3275: 
        !          3276:        if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
        !          3277:                if (error) {
        !          3278:                        spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
        !          3279:                }
        !          3280:                return EOF;
        !          3281:        }
        !          3282: 
        !          3283:        return EOF;
        !          3284: }
        !          3285: /* }}} */
        !          3286: 
        !          3287: #ifdef COMPILE_DL_PHAR
        !          3288: ZEND_GET_MODULE(phar)
        !          3289: #endif
        !          3290: 
        !          3291: /* {{{ phar_functions[]
        !          3292:  *
        !          3293:  * Every user visible function must have an entry in phar_functions[].
        !          3294:  */
        !          3295: zend_function_entry phar_functions[] = {
        !          3296:        PHP_FE_END
        !          3297: };
        !          3298: /* }}}*/
        !          3299: 
        !          3300: static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
        !          3301: {
        !          3302:        return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
        !          3303: }
        !          3304: /* }}} */
        !          3305: 
        !          3306: #if PHP_VERSION_ID >= 50300
        !          3307: static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
        !          3308: {
        !          3309:        return ((phar_archive_data*)handle)->halt_offset + 32;
        !          3310: } /* }}} */
        !          3311: 
        !          3312: #else /* PHP_VERSION_ID */
        !          3313: 
        !          3314: static long phar_stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
        !          3315: {
        !          3316:        return (long)php_stream_tell(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC));
        !          3317: }
        !          3318: /* }}} */
        !          3319: #endif
        !          3320: 
        !          3321: zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
        !          3322: #if PHP_VERSION_ID >= 50300
        !          3323: #define phar_orig_zend_open zend_stream_open_function
        !          3324: static char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
        !          3325: {
        !          3326:        return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
        !          3327: }
        !          3328: #else
        !          3329: int (*phar_orig_zend_open)(const char *filename, zend_file_handle *handle TSRMLS_DC);
        !          3330: #endif
        !          3331: 
        !          3332: static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
        !          3333: {
        !          3334:        zend_op_array *res;
        !          3335:        char *name = NULL;
        !          3336:        int failed;
        !          3337:        phar_archive_data *phar;
        !          3338: 
        !          3339:        if (!file_handle || !file_handle->filename) {
        !          3340:                return phar_orig_compile_file(file_handle, type TSRMLS_CC);
        !          3341:        }
        !          3342:        if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
        !          3343:                if (SUCCESS == phar_open_from_filename(file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
        !          3344:                        if (phar->is_zip || phar->is_tar) {
        !          3345:                                zend_file_handle f = *file_handle;
        !          3346: 
        !          3347:                                /* zip or tar-based phar */
        !          3348:                                spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
        !          3349:                                if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
        !          3350:                                        efree(name);
        !          3351:                                        name = NULL;
        !          3352:                                        file_handle->filename = f.filename;
        !          3353:                                        if (file_handle->opened_path) {
        !          3354:                                                efree(file_handle->opened_path);
        !          3355:                                        }
        !          3356:                                        file_handle->opened_path = f.opened_path;
        !          3357:                                        file_handle->free_filename = f.free_filename;
        !          3358:                                } else {
        !          3359:                                        *file_handle = f;
        !          3360:                                }
        !          3361:                        } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
        !          3362:                                /* compressed phar */
        !          3363: #if PHP_VERSION_ID >= 50300
        !          3364:                                file_handle->type = ZEND_HANDLE_STREAM;
        !          3365:                                /* we do our own reading directly from the phar, don't change the next line */
        !          3366:                                file_handle->handle.stream.handle  = phar;
        !          3367:                                file_handle->handle.stream.reader  = phar_zend_stream_reader;
        !          3368:                                file_handle->handle.stream.closer  = NULL;
        !          3369:                                file_handle->handle.stream.fsizer  = phar_zend_stream_fsizer;
        !          3370:                                file_handle->handle.stream.isatty  = 0;
        !          3371:                                phar->is_persistent ?
        !          3372:                                        php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
        !          3373:                                        php_stream_rewind(phar->fp);
        !          3374:                                memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
        !          3375: #else /* PHP_VERSION_ID */
        !          3376:                                file_handle->type = ZEND_HANDLE_STREAM;
        !          3377:                                /* we do our own reading directly from the phar, don't change the next line */
        !          3378:                                file_handle->handle.stream.handle = phar;
        !          3379:                                file_handle->handle.stream.reader = phar_zend_stream_reader;
        !          3380:                                file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */
        !          3381:                                file_handle->handle.stream.fteller = phar_stream_fteller_for_zend;
        !          3382:                                file_handle->handle.stream.interactive = 0;
        !          3383:                                phar->is_persistent ?
        !          3384:                                        php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
        !          3385:                                        php_stream_rewind(phar->fp);
        !          3386: #endif
        !          3387:                        }
        !          3388:                }
        !          3389:        }
        !          3390: 
        !          3391:        zend_try {
        !          3392:                failed = 0;
        !          3393:                res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
        !          3394:        } zend_catch {
        !          3395:                failed = 1;
        !          3396:                res = NULL;
        !          3397:        } zend_end_try();
        !          3398: 
        !          3399:        if (name) {
        !          3400:                efree(name);
        !          3401:        }
        !          3402: 
        !          3403:        if (failed) {
        !          3404:                zend_bailout();
        !          3405:        }
        !          3406: 
        !          3407:        return res;
        !          3408: }
        !          3409: /* }}} */
        !          3410: 
        !          3411: #if PHP_VERSION_ID < 50300
        !          3412: int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
        !          3413: {
        !          3414:        char *arch, *entry;
        !          3415:        int arch_len, entry_len;
        !          3416: 
        !          3417:        /* this code is obsoleted in php 5.3 */
        !          3418:        entry = (char *) filename;
        !          3419:        if (!IS_ABSOLUTE_PATH(entry, strlen(entry)) && !strstr(entry, "://")) {
        !          3420:                phar_archive_data **pphar = NULL;
        !          3421:                char *fname;
        !          3422:                int fname_len;
        !          3423: 
        !          3424:                fname = zend_get_executed_filename(TSRMLS_C);
        !          3425:                fname_len = strlen(fname);
        !          3426: 
        !          3427:                if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
        !          3428:                        if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
        !          3429:                                zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
        !          3430:                                if (!pphar && PHAR_G(manifest_cached)) {
        !          3431:                                        zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
        !          3432:                                }
        !          3433:                                efree(arch);
        !          3434:                                efree(entry);
        !          3435:                        }
        !          3436:                }
        !          3437: 
        !          3438:                /* retrieving an include within the current directory, so use this if possible */
        !          3439:                if (!(entry = phar_find_in_include_path((char *) filename, strlen(filename), NULL TSRMLS_CC))) {
        !          3440:                        /* this file is not in the phar, use the original path */
        !          3441:                        goto skip_phar;
        !          3442:                }
        !          3443: 
        !          3444:                if (SUCCESS == phar_orig_zend_open(entry, handle TSRMLS_CC)) {
        !          3445:                        if (!handle->opened_path) {
        !          3446:                                handle->opened_path = entry;
        !          3447:                        }
        !          3448:                        if (entry != filename) {
        !          3449:                                handle->free_filename = 1;
        !          3450:                        }
        !          3451:                        return SUCCESS;
        !          3452:                }
        !          3453: 
        !          3454:                if (entry != filename) {
        !          3455:                        efree(entry);
        !          3456:                }
        !          3457: 
        !          3458:                return FAILURE;
        !          3459:        }
        !          3460: skip_phar:
        !          3461:        return phar_orig_zend_open(filename, handle TSRMLS_CC);
        !          3462: }
        !          3463: /* }}} */
        !          3464: #endif
        !          3465: typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
        !          3466: typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
        !          3467: 
        !          3468: PHP_GINIT_FUNCTION(phar) /* {{{ */
        !          3469: {
        !          3470:        phar_mime_type mime;
        !          3471: 
        !          3472:        memset(phar_globals, 0, sizeof(zend_phar_globals));
        !          3473:        phar_globals->readonly = 1;
        !          3474: 
        !          3475:        zend_hash_init(&phar_globals->mime_types, 0, NULL, NULL, 1);
        !          3476: 
        !          3477: #define PHAR_SET_MIME(mimetype, ret, fileext) \
        !          3478:                mime.mime = mimetype; \
        !          3479:                mime.len = sizeof((mimetype))+1; \
        !          3480:                mime.type = ret; \
        !          3481:                zend_hash_add(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
        !          3482: 
        !          3483:        PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
        !          3484:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
        !          3485:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
        !          3486:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
        !          3487:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
        !          3488:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
        !          3489:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
        !          3490:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
        !          3491:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
        !          3492:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
        !          3493:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
        !          3494:        PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
        !          3495:        PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
        !          3496:        PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
        !          3497:        PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
        !          3498:        PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
        !          3499:        PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
        !          3500:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
        !          3501:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
        !          3502:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
        !          3503:        PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
        !          3504:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
        !          3505:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
        !          3506:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
        !          3507:        PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
        !          3508:        PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
        !          3509:        PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
        !          3510:        PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
        !          3511:        PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
        !          3512:        PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
        !          3513:        PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
        !          3514:        PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
        !          3515:        PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
        !          3516:        PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
        !          3517:        PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
        !          3518:        PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
        !          3519:        PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
        !          3520:        PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
        !          3521:        PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
        !          3522:        PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
        !          3523: 
        !          3524:        phar_restore_orig_functions(TSRMLS_C);
        !          3525: }
        !          3526: /* }}} */
        !          3527: 
        !          3528: PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
        !          3529: {
        !          3530:        zend_hash_destroy(&phar_globals->mime_types);
        !          3531: }
        !          3532: /* }}} */
        !          3533: 
        !          3534: PHP_MINIT_FUNCTION(phar) /* {{{ */
        !          3535: {
        !          3536:        REGISTER_INI_ENTRIES();
        !          3537: 
        !          3538:        phar_orig_compile_file = zend_compile_file;
        !          3539:        zend_compile_file = phar_compile_file;
        !          3540: 
        !          3541: #if PHP_VERSION_ID >= 50300
        !          3542:        phar_save_resolve_path = zend_resolve_path;
        !          3543:        zend_resolve_path = phar_resolve_path;
        !          3544: #else
        !          3545:        phar_orig_zend_open = zend_stream_open_function;
        !          3546:        zend_stream_open_function = phar_zend_open;
        !          3547: #endif
        !          3548: 
        !          3549:        phar_object_init(TSRMLS_C);
        !          3550: 
        !          3551:        phar_intercept_functions_init(TSRMLS_C);
        !          3552:        phar_save_orig_functions(TSRMLS_C);
        !          3553: 
        !          3554:        return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
        !          3555: }
        !          3556: /* }}} */
        !          3557: 
        !          3558: PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
        !          3559: {
        !          3560:        php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
        !          3561: 
        !          3562:        phar_intercept_functions_shutdown(TSRMLS_C);
        !          3563: 
        !          3564:        if (zend_compile_file == phar_compile_file) {
        !          3565:                zend_compile_file = phar_orig_compile_file;
        !          3566:        }
        !          3567: 
        !          3568: #if PHP_VERSION_ID < 50300
        !          3569:        if (zend_stream_open_function == phar_zend_open) {
        !          3570:                zend_stream_open_function = phar_orig_zend_open;
        !          3571:        }
        !          3572: #endif
        !          3573:        if (PHAR_G(manifest_cached)) {
        !          3574:                zend_hash_destroy(&(cached_phars));
        !          3575:                zend_hash_destroy(&(cached_alias));
        !          3576:        }
        !          3577: 
        !          3578:        return SUCCESS;
        !          3579: }
        !          3580: /* }}} */
        !          3581: 
        !          3582: void phar_request_initialize(TSRMLS_D) /* {{{ */
        !          3583: {
        !          3584:        if (!PHAR_GLOBALS->request_init)
        !          3585:        {
        !          3586:                PHAR_G(last_phar) = NULL;
        !          3587:                PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
        !          3588:                PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
        !          3589:                PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
        !          3590:                PHAR_GLOBALS->request_init = 1;
        !          3591:                PHAR_GLOBALS->request_ends = 0;
        !          3592:                PHAR_GLOBALS->request_done = 0;
        !          3593:                zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data,  0);
        !          3594:                zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL,  0);
        !          3595:                zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
        !          3596: 
        !          3597:                if (PHAR_G(manifest_cached)) {
        !          3598:                        phar_archive_data **pphar;
        !          3599:                        phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
        !          3600: 
        !          3601:                        for (zend_hash_internal_pointer_reset(&cached_phars);
        !          3602:                        zend_hash_get_current_data(&cached_phars, (void **)&pphar) == SUCCESS;
        !          3603:                        zend_hash_move_forward(&cached_phars)) {
        !          3604:                                stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
        !          3605:                        }
        !          3606: 
        !          3607:                        PHAR_GLOBALS->cached_fp = stuff;
        !          3608:                }
        !          3609: 
        !          3610:                PHAR_GLOBALS->phar_SERVER_mung_list = 0;
        !          3611:                PHAR_G(cwd) = NULL;
        !          3612:                PHAR_G(cwd_len) = 0;
        !          3613:                PHAR_G(cwd_init) = 0;
        !          3614:        }
        !          3615: }
        !          3616: /* }}} */
        !          3617: 
        !          3618: PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
        !          3619: {
        !          3620:        int i;
        !          3621: 
        !          3622:        PHAR_GLOBALS->request_ends = 1;
        !          3623: 
        !          3624:        if (PHAR_GLOBALS->request_init)
        !          3625:        {
        !          3626:                phar_release_functions(TSRMLS_C);
        !          3627:                zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
        !          3628:                PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
        !          3629:                zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
        !          3630:                PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
        !          3631:                zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
        !          3632:                PHAR_GLOBALS->phar_persist_map.arBuckets = NULL;
        !          3633:                PHAR_GLOBALS->phar_SERVER_mung_list = 0;
        !          3634: 
        !          3635:                if (PHAR_GLOBALS->cached_fp) {
        !          3636:                        for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
        !          3637:                                if (PHAR_GLOBALS->cached_fp[i].fp) {
        !          3638:                                        php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
        !          3639:                                }
        !          3640:                                if (PHAR_GLOBALS->cached_fp[i].ufp) {
        !          3641:                                        php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
        !          3642:                                }
        !          3643:                                efree(PHAR_GLOBALS->cached_fp[i].manifest);
        !          3644:                        }
        !          3645:                        efree(PHAR_GLOBALS->cached_fp);
        !          3646:                        PHAR_GLOBALS->cached_fp = 0;
        !          3647:                }
        !          3648: 
        !          3649:                PHAR_GLOBALS->request_init = 0;
        !          3650: 
        !          3651:                if (PHAR_G(cwd)) {
        !          3652:                        efree(PHAR_G(cwd));
        !          3653:                }
        !          3654: 
        !          3655:                PHAR_G(cwd) = NULL;
        !          3656:                PHAR_G(cwd_len) = 0;
        !          3657:                PHAR_G(cwd_init) = 0;
        !          3658:        }
        !          3659: 
        !          3660:        PHAR_GLOBALS->request_done = 1;
        !          3661:        return SUCCESS;
        !          3662: }
        !          3663: /* }}} */
        !          3664: 
        !          3665: PHP_MINFO_FUNCTION(phar) /* {{{ */
        !          3666: {
        !          3667:        phar_request_initialize(TSRMLS_C);
        !          3668:        php_info_print_table_start();
        !          3669:        php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
        !          3670:        php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
        !          3671:        php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
        !          3672:        php_info_print_table_row(2, "SVN revision", "$Revision: 321634 $");
        !          3673:        php_info_print_table_row(2, "Phar-based phar archives", "enabled");
        !          3674:        php_info_print_table_row(2, "Tar-based phar archives", "enabled");
        !          3675:        php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
        !          3676: 
        !          3677:        if (PHAR_G(has_zlib)) {
        !          3678:                php_info_print_table_row(2, "gzip compression", "enabled");
        !          3679:        } else {
        !          3680:                php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
        !          3681:        }
        !          3682: 
        !          3683:        if (PHAR_G(has_bz2)) {
        !          3684:                php_info_print_table_row(2, "bzip2 compression", "enabled");
        !          3685:        } else {
        !          3686:                php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
        !          3687:        }
        !          3688: #ifdef PHAR_HAVE_OPENSSL
        !          3689:        php_info_print_table_row(2, "Native OpenSSL support", "enabled");
        !          3690: #else
        !          3691:        if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
        !          3692:                php_info_print_table_row(2, "OpenSSL support", "enabled");
        !          3693:        } else {
        !          3694:                php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
        !          3695:        }
        !          3696: #endif
        !          3697:        php_info_print_table_end();
        !          3698: 
        !          3699:        php_info_print_box_start(0);
        !          3700:        PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
        !          3701:        PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
        !          3702:        PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
        !          3703:        PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
        !          3704:        PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
        !          3705:        php_info_print_box_end();
        !          3706: 
        !          3707:        DISPLAY_INI_ENTRIES();
        !          3708: }
        !          3709: /* }}} */
        !          3710: 
        !          3711: /* {{{ phar_module_entry
        !          3712:  */
        !          3713: static const zend_module_dep phar_deps[] = {
        !          3714:        ZEND_MOD_OPTIONAL("apc")
        !          3715:        ZEND_MOD_OPTIONAL("bz2")
        !          3716:        ZEND_MOD_OPTIONAL("openssl")
        !          3717:        ZEND_MOD_OPTIONAL("zlib")
        !          3718:        ZEND_MOD_OPTIONAL("standard")
        !          3719: #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
        !          3720:        ZEND_MOD_REQUIRED("hash")
        !          3721: #endif
        !          3722: #if HAVE_SPL
        !          3723:        ZEND_MOD_REQUIRED("spl")
        !          3724: #endif
        !          3725:        ZEND_MOD_END
        !          3726: };
        !          3727: 
        !          3728: zend_module_entry phar_module_entry = {
        !          3729:        STANDARD_MODULE_HEADER_EX, NULL,
        !          3730:        phar_deps,
        !          3731:        "Phar",
        !          3732:        phar_functions,
        !          3733:        PHP_MINIT(phar),
        !          3734:        PHP_MSHUTDOWN(phar),
        !          3735:        NULL,
        !          3736:        PHP_RSHUTDOWN(phar),
        !          3737:        PHP_MINFO(phar),
        !          3738:        PHP_PHAR_VERSION,
        !          3739:        PHP_MODULE_GLOBALS(phar),   /* globals descriptor */
        !          3740:        PHP_GINIT(phar),            /* globals ctor */
        !          3741:        PHP_GSHUTDOWN(phar),        /* globals dtor */
        !          3742:        NULL,                       /* post deactivate */
        !          3743:        STANDARD_MODULE_PROPERTIES_EX
        !          3744: };
        !          3745: /* }}} */
        !          3746: 
        !          3747: /*
        !          3748:  * Local variables:
        !          3749:  * tab-width: 4
        !          3750:  * c-basic-offset: 4
        !          3751:  * End:
        !          3752:  * vim600: noet sw=4 ts=4 fdm=marker
        !          3753:  * vim<600: noet sw=4 ts=4
        !          3754:  */

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