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

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | phar php single-file executable PHP extension                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:   | Copyright (c) 2005-2013 The PHP Group                                |
1.1       misho       6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt.                                 |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Authors: Gregory Beaver <cellog@php.net>                             |
                     16:   |          Marcus Boerger <helly@php.net>                              |
                     17:   +----------------------------------------------------------------------+
                     18: */
                     19: 
1.1.1.3 ! misho      20: /* $Id: c5042cc34acebcc0926625b57dff03deebbe6472 $ */
1.1       misho      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;
1.1.1.2   misho    1741:        char *realpath;
                   1742:        char *filename = estrndup(fname, (ext - fname) + ext_len);
1.1       misho    1743: 
1.1.1.2   misho    1744:        if ((realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
1.1       misho    1745: #ifdef PHP_WIN32
                   1746:                phar_unixify_path_separators(realpath, strlen(realpath));
                   1747: #endif
                   1748:                if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
                   1749:                        efree(realpath);
1.1.1.2   misho    1750:                        efree(filename);
1.1       misho    1751:                        return SUCCESS;
                   1752:                }
                   1753: 
                   1754:                if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
                   1755:                        efree(realpath);
1.1.1.2   misho    1756:                        efree(filename);
1.1       misho    1757:                        return SUCCESS;
                   1758:                }
                   1759:                efree(realpath);
                   1760:        }
                   1761: 
1.1.1.2   misho    1762:        if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
                   1763: 
                   1764:                efree(filename);
1.1       misho    1765: 
                   1766:                if (ssb.sb.st_mode & S_IFDIR) {
                   1767:                        return FAILURE;
                   1768:                }
                   1769: 
                   1770:                if (for_create == 1) {
                   1771:                        return FAILURE;
                   1772:                }
                   1773: 
                   1774:                return SUCCESS;
                   1775:        } else {
                   1776:                char *slash;
                   1777: 
                   1778:                if (!for_create) {
1.1.1.2   misho    1779:                        efree(filename);
1.1       misho    1780:                        return FAILURE;
                   1781:                }
                   1782: 
1.1.1.2   misho    1783:                slash = (char *) strrchr(filename, '/');
1.1       misho    1784: 
                   1785:                if (slash) {
                   1786:                        *slash = '\0';
                   1787:                }
                   1788: 
1.1.1.2   misho    1789:                if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
                   1790:                        if (!slash) {
                   1791:                                if (!(realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
                   1792:                                        efree(filename);
1.1       misho    1793:                                        return FAILURE;
                   1794:                                }
                   1795: #ifdef PHP_WIN32
                   1796:                                phar_unixify_path_separators(realpath, strlen(realpath));
                   1797: #endif
1.1.1.2   misho    1798:                                slash = strstr(realpath, filename) + ((ext - fname) + ext_len);
                   1799:                                *slash = '\0';
1.1       misho    1800:                                slash = strrchr(realpath, '/');
                   1801: 
                   1802:                                if (slash) {
                   1803:                                        *slash = '\0';
                   1804:                                } else {
                   1805:                                        efree(realpath);
1.1.1.2   misho    1806:                                        efree(filename);
1.1       misho    1807:                                        return FAILURE;
                   1808:                                }
                   1809: 
                   1810:                                if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
                   1811:                                        efree(realpath);
1.1.1.2   misho    1812:                                        efree(filename);
1.1       misho    1813:                                        return FAILURE;
                   1814:                                }
                   1815: 
                   1816:                                efree(realpath);
                   1817: 
                   1818:                                if (ssb.sb.st_mode & S_IFDIR) {
1.1.1.2   misho    1819:                                        efree(filename);
1.1       misho    1820:                                        return SUCCESS;
                   1821:                                }
                   1822:                        }
                   1823: 
1.1.1.2   misho    1824:                        efree(filename);
1.1       misho    1825:                        return FAILURE;
                   1826:                }
                   1827: 
1.1.1.2   misho    1828:                efree(filename);
1.1       misho    1829: 
                   1830:                if (ssb.sb.st_mode & S_IFDIR) {
                   1831:                        return SUCCESS;
                   1832:                }
                   1833: 
                   1834:                return FAILURE;
                   1835:        }
                   1836: }
                   1837: /* }}} */
                   1838: 
                   1839: /* check for ".phar" in extension */
                   1840: static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC) /* {{{ */
                   1841: {
                   1842:        char test[51];
                   1843:        const char *pos;
                   1844: 
                   1845:        if (ext_len >= 50) {
                   1846:                return FAILURE;
                   1847:        }
                   1848: 
                   1849:        if (executable == 1) {
                   1850:                /* copy "." as well */
                   1851:                memcpy(test, ext_str - 1, ext_len + 1);
                   1852:                test[ext_len + 1] = '\0';
                   1853:                /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
                   1854:                /* (phar://hi/there/.phar/oops is also invalid) */
                   1855:                pos = strstr(test, ".phar");
                   1856: 
                   1857:                if (pos && (*(pos - 1) != '/')
                   1858:                                && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
                   1859:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
                   1860:                } else {
                   1861:                        return FAILURE;
                   1862:                }
                   1863:        }
                   1864: 
                   1865:        /* data phars need only contain a single non-"." to be valid */
                   1866:        if (!executable) {
                   1867:                pos = strstr(ext_str, ".phar");
                   1868:                if (!(pos && (*(pos - 1) != '/')
                   1869:                                        && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
                   1870:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
                   1871:                }
                   1872:        } else {
                   1873:                if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
                   1874:                        return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
                   1875:                }
                   1876:        }
                   1877: 
                   1878:        return FAILURE;
                   1879: }
                   1880: /* }}} */
                   1881: 
                   1882: /*
                   1883:  * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
                   1884:  * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
                   1885:  * the first extension as the filename extension
                   1886:  *
                   1887:  * if an extension is found, it sets ext_str to the location of the file extension in filename,
                   1888:  * and ext_len to the length of the extension.
                   1889:  * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
                   1890:  * the calling function to use "alias" as the phar alias
                   1891:  *
                   1892:  * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
                   1893:  * extension rules, not to iterate.
                   1894:  */
                   1895: 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) /* {{{ */
                   1896: {
                   1897:        const char *pos, *slash;
                   1898: 
                   1899:        *ext_str = NULL;
                   1900:        *ext_len = 0;
                   1901: 
                   1902:        if (!filename_len || filename_len == 1) {
                   1903:                return FAILURE;
                   1904:        }
                   1905: 
                   1906:        phar_request_initialize(TSRMLS_C);
                   1907:        /* first check for alias in first segment */
                   1908:        pos = memchr(filename, '/', filename_len);
                   1909: 
                   1910:        if (pos && pos != filename) {
                   1911:                /* check for url like http:// or phar:// */
                   1912:                if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
                   1913:                        *ext_len = -2;
                   1914:                        *ext_str = NULL;
                   1915:                        return FAILURE;
                   1916:                }
                   1917:                if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
                   1918:                        *ext_str = pos;
                   1919:                        *ext_len = -1;
                   1920:                        return FAILURE;
                   1921:                }
                   1922: 
                   1923:                if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
                   1924:                        *ext_str = pos;
                   1925:                        *ext_len = -1;
                   1926:                        return FAILURE;
                   1927:                }
                   1928:        }
                   1929: 
                   1930:        if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
                   1931:                phar_archive_data **pphar;
                   1932: 
                   1933:                if (is_complete) {
                   1934:                        if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) {
                   1935:                                *ext_str = filename + (filename_len - (*pphar)->ext_len);
                   1936: woohoo:
                   1937:                                *ext_len = (*pphar)->ext_len;
                   1938: 
                   1939:                                if (executable == 2) {
                   1940:                                        return SUCCESS;
                   1941:                                }
                   1942: 
                   1943:                                if (executable == 1 && !(*pphar)->is_data) {
                   1944:                                        return SUCCESS;
                   1945:                                }
                   1946: 
                   1947:                                if (!executable && (*pphar)->is_data) {
                   1948:                                        return SUCCESS;
                   1949:                                }
                   1950: 
                   1951:                                return FAILURE;
                   1952:                        }
                   1953: 
                   1954:                        if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
                   1955:                                *ext_str = filename + (filename_len - (*pphar)->ext_len);
                   1956:                                goto woohoo;
                   1957:                        }
                   1958:                } else {
                   1959:                        phar_zstr key;
                   1960:                        char *str_key;
                   1961:                        uint keylen;
                   1962:                        ulong unused;
                   1963: 
                   1964:                        zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
                   1965: 
                   1966:                        while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) {
                   1967:                                if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) {
                   1968:                                        break;
                   1969:                                }
                   1970: 
                   1971:                                PHAR_STR(key, str_key);
                   1972: 
                   1973:                                if (keylen > (uint) filename_len) {
                   1974:                                        zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
                   1975:                                        PHAR_STR_FREE(str_key);
                   1976:                                        continue;
                   1977:                                }
                   1978: 
                   1979:                                if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
                   1980:                                        || filename[keylen] == '/' || filename[keylen] == '\0')) {
                   1981:                                        PHAR_STR_FREE(str_key);
                   1982:                                        if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
                   1983:                                                break;
                   1984:                                        }
                   1985:                                        *ext_str = filename + (keylen - (*pphar)->ext_len);
                   1986:                                        goto woohoo;
                   1987:                                }
                   1988: 
                   1989:                                PHAR_STR_FREE(str_key);
                   1990:                                zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
                   1991:                        }
                   1992: 
                   1993:                        if (PHAR_G(manifest_cached)) {
                   1994:                                zend_hash_internal_pointer_reset(&cached_phars);
                   1995: 
                   1996:                                while (FAILURE != zend_hash_has_more_elements(&cached_phars)) {
                   1997:                                        if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&cached_phars, &key, &keylen, &unused, 0, NULL)) {
                   1998:                                                break;
                   1999:                                        }
                   2000: 
                   2001:                                        PHAR_STR(key, str_key);
                   2002: 
                   2003:                                        if (keylen > (uint) filename_len) {
                   2004:                                                zend_hash_move_forward(&cached_phars);
                   2005:                                                PHAR_STR_FREE(str_key);
                   2006:                                                continue;
                   2007:                                        }
                   2008: 
                   2009:                                        if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
                   2010:                                                || filename[keylen] == '/' || filename[keylen] == '\0')) {
                   2011:                                                PHAR_STR_FREE(str_key);
                   2012:                                                if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
                   2013:                                                        break;
                   2014:                                                }
                   2015:                                                *ext_str = filename + (keylen - (*pphar)->ext_len);
                   2016:                                                goto woohoo;
                   2017:                                        }
                   2018:                                        PHAR_STR_FREE(str_key);
                   2019:                                        zend_hash_move_forward(&cached_phars);
                   2020:                                }
                   2021:                        }
                   2022:                }
                   2023:        }
                   2024: 
                   2025:        pos = memchr(filename + 1, '.', filename_len);
                   2026: next_extension:
                   2027:        if (!pos) {
                   2028:                return FAILURE;
                   2029:        }
                   2030: 
                   2031:        while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
                   2032:                pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1);
                   2033:                if (!pos) {
                   2034:                        return FAILURE;
                   2035:                }
                   2036:        }
                   2037: 
                   2038:        slash = memchr(pos, '/', filename_len - (pos - filename));
                   2039: 
                   2040:        if (!slash) {
                   2041:                /* this is a url like "phar://blah.phar" with no directory */
                   2042:                *ext_str = pos;
                   2043:                *ext_len = strlen(pos);
                   2044: 
                   2045:                /* file extension must contain "phar" */
                   2046:                switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
                   2047:                        case SUCCESS:
                   2048:                                return SUCCESS;
                   2049:                        case FAILURE:
                   2050:                                /* we are at the end of the string, so we fail */
                   2051:                                return FAILURE;
                   2052:                }
                   2053:        }
                   2054: 
                   2055:        /* we've found an extension that ends at a directory separator */
                   2056:        *ext_str = pos;
                   2057:        *ext_len = slash - pos;
                   2058: 
                   2059:        switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
                   2060:                case SUCCESS:
                   2061:                        return SUCCESS;
                   2062:                case FAILURE:
                   2063:                        /* look for more extensions */
                   2064:                        pos = strchr(pos + 1, '.');
                   2065:                        if (pos) {
                   2066:                                *ext_str = NULL;
                   2067:                                *ext_len = 0;
                   2068:                        }
                   2069:                        goto next_extension;
                   2070:        }
                   2071: 
                   2072:        return FAILURE;
                   2073: }
                   2074: /* }}} */
                   2075: 
                   2076: static int php_check_dots(const char *element, int n) /* {{{ */
                   2077: {
                   2078:        for(n--; n >= 0; --n) {
                   2079:                if (element[n] != '.') {
                   2080:                        return 1;
                   2081:                }
                   2082:        }
                   2083:        return 0;
                   2084: }
                   2085: /* }}} */
                   2086: 
                   2087: #define IS_DIRECTORY_UP(element, len) \
                   2088:        (len >= 2 && !php_check_dots(element, len))
                   2089: 
                   2090: #define IS_DIRECTORY_CURRENT(element, len) \
                   2091:        (len == 1 && element[0] == '.')
                   2092: 
                   2093: #define IS_BACKSLASH(c) ((c) == '/')
                   2094: 
                   2095: #ifdef COMPILE_DL_PHAR
                   2096: /* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */
                   2097: static inline int in_character_class(char ch, const char *delim) /* {{{ */
                   2098: {
                   2099:        while (*delim) {
                   2100:                if (*delim == ch) {
                   2101:                        return 1;
                   2102:                }
                   2103:                ++delim;
                   2104:        }
                   2105:        return 0;
                   2106: }
                   2107: /* }}} */
                   2108: 
                   2109: char *tsrm_strtok_r(char *s, const char *delim, char **last) /* {{{ */
                   2110: {
                   2111:        char *token;
                   2112: 
                   2113:        if (s == NULL) {
                   2114:                s = *last;
                   2115:        }
                   2116: 
                   2117:        while (*s && in_character_class(*s, delim)) {
                   2118:                ++s;
                   2119:        }
                   2120: 
                   2121:        if (!*s) {
                   2122:                return NULL;
                   2123:        }
                   2124: 
                   2125:        token = s;
                   2126: 
                   2127:        while (*s && !in_character_class(*s, delim)) {
                   2128:                ++s;
                   2129:        }
                   2130: 
                   2131:        if (!*s) {
                   2132:                *last = s;
                   2133:        } else {
                   2134:                *s = '\0';
                   2135:                *last = s + 1;
                   2136:        }
                   2137: 
                   2138:        return token;
                   2139: }
                   2140: /* }}} */
                   2141: #endif
                   2142: 
                   2143: /**
                   2144:  * Remove .. and . references within a phar filename
                   2145:  */
                   2146: char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
                   2147: {
                   2148:        char newpath[MAXPATHLEN];
                   2149:        int newpath_len;
                   2150:        char *ptr;
                   2151:        char *tok;
                   2152:        int ptr_length, path_length = *new_len;
                   2153: 
                   2154:        if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
                   2155:                newpath_len = PHAR_G(cwd_len);
                   2156:                memcpy(newpath, PHAR_G(cwd), newpath_len);
                   2157:        } else {
                   2158:                newpath[0] = '/';
                   2159:                newpath_len = 1;
                   2160:        }
                   2161: 
                   2162:        ptr = path;
                   2163: 
                   2164:        if (*ptr == '/') {
                   2165:                ++ptr;
                   2166:        }
                   2167: 
                   2168:        tok = ptr;
                   2169: 
                   2170:        do {
                   2171:                ptr = memchr(ptr, '/', path_length - (ptr - path));
                   2172:        } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
                   2173: 
                   2174:        if (!ptr && (path_length - (tok - path))) {
                   2175:                switch (path_length - (tok - path)) {
                   2176:                        case 1:
                   2177:                                if (*tok == '.') {
                   2178:                                        efree(path);
                   2179:                                        *new_len = 1;
                   2180:                                        return estrndup("/", 1);
                   2181:                                }
                   2182:                                break;
                   2183:                        case 2:
                   2184:                                if (tok[0] == '.' && tok[1] == '.') {
                   2185:                                        efree(path);
                   2186:                                        *new_len = 1;
                   2187:                                        return estrndup("/", 1);
                   2188:                                }
                   2189:                }
                   2190:                return path;
                   2191:        }
                   2192: 
                   2193:        while (ptr) {
                   2194:                ptr_length = ptr - tok;
                   2195: last_time:
                   2196:                if (IS_DIRECTORY_UP(tok, ptr_length)) {
                   2197: #define PREVIOUS newpath[newpath_len - 1]
                   2198: 
                   2199:                        while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
                   2200:                                newpath_len--;
                   2201:                        }
                   2202: 
                   2203:                        if (newpath[0] != '/') {
                   2204:                                newpath[newpath_len] = '\0';
                   2205:                        } else if (newpath_len > 1) {
                   2206:                                --newpath_len;
                   2207:                        }
                   2208:                } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
                   2209:                        if (newpath_len > 1) {
                   2210:                                newpath[newpath_len++] = '/';
                   2211:                                memcpy(newpath + newpath_len, tok, ptr_length+1);
                   2212:                        } else {
                   2213:                                memcpy(newpath + newpath_len, tok, ptr_length+1);
                   2214:                        }
                   2215: 
                   2216:                        newpath_len += ptr_length;
                   2217:                }
                   2218: 
                   2219:                if (ptr == path + path_length) {
                   2220:                        break;
                   2221:                }
                   2222: 
                   2223:                tok = ++ptr;
                   2224: 
                   2225:                do {
                   2226:                        ptr = memchr(ptr, '/', path_length - (ptr - path));
                   2227:                } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
                   2228: 
                   2229:                if (!ptr && (path_length - (tok - path))) {
                   2230:                        ptr_length = path_length - (tok - path);
                   2231:                        ptr = path + path_length;
                   2232:                        goto last_time;
                   2233:                }
                   2234:        }
                   2235: 
                   2236:        efree(path);
                   2237:        *new_len = newpath_len;
                   2238:        return estrndup(newpath, newpath_len);
                   2239: }
                   2240: /* }}} */
                   2241: 
                   2242: /**
                   2243:  * Process a phar stream name, ensuring we can handle any of:
                   2244:  * 
                   2245:  * - whatever.phar
                   2246:  * - whatever.phar.gz
                   2247:  * - whatever.phar.bz2
                   2248:  * - whatever.phar.php
                   2249:  *
                   2250:  * Optionally the name might start with 'phar://'
                   2251:  *
                   2252:  * This is used by phar_parse_url()
                   2253:  */
                   2254: 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) /* {{{ */
                   2255: {
                   2256:        const char *ext_str;
                   2257: #ifdef PHP_WIN32
                   2258:        char *save;
                   2259: #endif
                   2260:        int ext_len, free_filename = 0;
                   2261: 
                   2262:        if (!strncasecmp(filename, "phar://", 7)) {
                   2263:                filename += 7;
                   2264:                filename_len -= 7;
                   2265:        }
                   2266: 
                   2267:        ext_len = 0;
                   2268: #ifdef PHP_WIN32
                   2269:        free_filename = 1;
                   2270:        save = filename;
                   2271:        filename = estrndup(filename, filename_len);
                   2272:        phar_unixify_path_separators(filename, filename_len);
                   2273: #endif
                   2274:        if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
                   2275:                if (ext_len != -1) {
                   2276:                        if (!ext_str) {
                   2277:                                /* no / detected, restore arch for error message */
                   2278: #ifdef PHP_WIN32
                   2279:                                *arch = save;
                   2280: #else
                   2281:                                *arch = filename;
                   2282: #endif
                   2283:                        }
                   2284: 
                   2285:                        if (free_filename) {
                   2286:                                efree(filename);
                   2287:                        }
                   2288: 
                   2289:                        return FAILURE;
                   2290:                }
                   2291: 
                   2292:                ext_len = 0;
                   2293:                /* no extension detected - instead we are dealing with an alias */
                   2294:        }
                   2295: 
                   2296:        *arch_len = ext_str - filename + ext_len;
                   2297:        *arch = estrndup(filename, *arch_len);
                   2298: 
                   2299:        if (ext_str[ext_len]) {
                   2300:                *entry_len = filename_len - *arch_len;
                   2301:                *entry = estrndup(ext_str+ext_len, *entry_len);
                   2302: #ifdef PHP_WIN32
                   2303:                phar_unixify_path_separators(*entry, *entry_len);
                   2304: #endif
                   2305:                *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
                   2306:        } else {
                   2307:                *entry_len = 1;
                   2308:                *entry = estrndup("/", 1);
                   2309:        }
                   2310: 
                   2311:        if (free_filename) {
                   2312:                efree(filename);
                   2313:        }
                   2314: 
                   2315:        return SUCCESS;
                   2316: }
                   2317: /* }}} */
                   2318: 
                   2319: /**
                   2320:  * Invoked when a user calls Phar::mapPhar() from within an executing .phar
                   2321:  * to set up its manifest directly
                   2322:  */
                   2323: int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
                   2324: {
                   2325:        char *fname;
                   2326:        zval *halt_constant;
                   2327:        php_stream *fp;
                   2328:        int fname_len;
                   2329:        char *actual = NULL;
                   2330:        int ret;
                   2331: 
                   2332:        if (error) {
                   2333:                *error = NULL;
                   2334:        }
                   2335: 
1.1.1.2   misho    2336:        fname = (char*)zend_get_executed_filename(TSRMLS_C);
1.1       misho    2337:        fname_len = strlen(fname);
                   2338: 
                   2339:        if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
                   2340:                return SUCCESS;
                   2341:        }
                   2342: 
                   2343:        if (!strcmp(fname, "[no active file]")) {
                   2344:                if (error) {
                   2345:                        spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
                   2346:                }
                   2347:                return FAILURE;
                   2348:        }
                   2349: 
                   2350:        MAKE_STD_ZVAL(halt_constant);
                   2351: 
                   2352:        if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
                   2353:                FREE_ZVAL(halt_constant);
                   2354:                if (error) {
                   2355:                        spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
                   2356:                }
                   2357:                return FAILURE;
                   2358:        }
                   2359: 
                   2360:        FREE_ZVAL(halt_constant);
                   2361: 
                   2362: #if PHP_API_VERSION < 20100412
                   2363:        if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
                   2364:                return FAILURE;
                   2365:        }
                   2366: #endif
                   2367: 
                   2368:        if (php_check_open_basedir(fname TSRMLS_CC)) {
                   2369:                return FAILURE;
                   2370:        }
                   2371: 
                   2372:        fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
                   2373: 
                   2374:        if (!fp) {
                   2375:                if (error) {
                   2376:                        spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
                   2377:                }
                   2378:                if (actual) {
                   2379:                        efree(actual);
                   2380:                }
                   2381:                return FAILURE;
                   2382:        }
                   2383: 
                   2384:        if (actual) {
                   2385:                fname = actual;
                   2386:                fname_len = strlen(actual);
                   2387:        }
                   2388: 
                   2389:        ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error TSRMLS_CC);
                   2390: 
                   2391:        if (actual) {
                   2392:                efree(actual);
                   2393:        }
                   2394: 
                   2395:        return ret;
                   2396: }
                   2397: /* }}} */
                   2398: 
                   2399: /**
                   2400:  * Validate the CRC32 of a file opened from within the phar
                   2401:  */
                   2402: int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
                   2403: {
                   2404:        php_uint32 crc = ~0;
                   2405:        int len = idata->internal_file->uncompressed_filesize;
                   2406:        php_stream *fp = idata->fp;
                   2407:        phar_entry_info *entry = idata->internal_file;
                   2408: 
                   2409:        if (error) {
                   2410:                *error = NULL;
                   2411:        }
                   2412: 
                   2413:        if (entry->is_zip && process_zip > 0) {
                   2414:                /* verify local file header */
                   2415:                phar_zip_file_header local;
                   2416:                phar_zip_data_desc desc;
                   2417: 
                   2418:                if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
                   2419:                        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);
                   2420:                        return FAILURE;
                   2421:                }
                   2422:                php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
                   2423: 
                   2424:                if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
                   2425: 
                   2426:                        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);
                   2427:                        return FAILURE;
                   2428:                }
                   2429: 
                   2430:                /* check for data descriptor */
                   2431:                if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
                   2432:                        php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
                   2433:                                        entry->header_offset + sizeof(local) +
                   2434:                                        PHAR_ZIP_16(local.filename_len) +
                   2435:                                        PHAR_ZIP_16(local.extra_len) +
                   2436:                                        entry->compressed_filesize, SEEK_SET);
                   2437:                        if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
                   2438:                                                            (char *) &desc, sizeof(desc))) {
                   2439:                                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);
                   2440:                                return FAILURE;
                   2441:                        }
                   2442:                        if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
                   2443:                                memcpy(&(local.crc32), &(desc.crc32), 12);
                   2444:                        } else {
                   2445:                                /* old data descriptors have no signature */
                   2446:                                memcpy(&(local.crc32), &desc, 12);
                   2447:                        }
                   2448:                }
                   2449:                /* verify local header */
                   2450:                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)) {
                   2451:                        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);
                   2452:                        return FAILURE;
                   2453:                }
                   2454: 
                   2455:                /* construct actual offset to file start - local extra_len can be different from central extra_len */
                   2456:                entry->offset = entry->offset_abs =
                   2457:                        sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
                   2458: 
                   2459:                if (idata->zero && idata->zero != entry->offset_abs) {
                   2460:                        idata->zero = entry->offset_abs;
                   2461:                }
                   2462:        }
                   2463: 
                   2464:        if (process_zip == 1) {
                   2465:                return SUCCESS;
                   2466:        }
                   2467: 
                   2468:        php_stream_seek(fp, idata->zero, SEEK_SET);
                   2469: 
                   2470:        while (len--) {
                   2471:                CRC32(crc, php_stream_getc(fp));
                   2472:        }
                   2473: 
                   2474:        php_stream_seek(fp, idata->zero, SEEK_SET);
                   2475: 
                   2476:        if (~crc == crc32) {
                   2477:                entry->is_crc_checked = 1;
                   2478:                return SUCCESS;
                   2479:        } else {
                   2480:                spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
                   2481:                return FAILURE;
                   2482:        }
                   2483: }
                   2484: /* }}} */
                   2485: 
                   2486: static inline void phar_set_32(char *buffer, int var) /* {{{ */
                   2487: {
                   2488: #ifdef WORDS_BIGENDIAN
                   2489:        *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
                   2490:        *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
                   2491:        *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
                   2492:        *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
                   2493: #else
                   2494:         memcpy(buffer, &var, sizeof(var));
                   2495: #endif
                   2496: } /* }}} */
                   2497: 
                   2498: static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */
                   2499: {
                   2500:        phar_entry_info *entry = (phar_entry_info *)data;
                   2501: 
                   2502:        if (entry->fp_refcount <= 0 && entry->is_deleted) {
                   2503:                return ZEND_HASH_APPLY_REMOVE;
                   2504:        } else {
                   2505:                return ZEND_HASH_APPLY_KEEP;
                   2506:        }
                   2507: }
                   2508: /* }}} */
                   2509: 
                   2510: #include "stub.h"
                   2511: 
                   2512: char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) /* {{{ */
                   2513: {
                   2514:        char *stub = NULL;
                   2515:        int index_len, web_len;
                   2516:        size_t dummy;
                   2517: 
                   2518:        if (!len) {
                   2519:                len = &dummy;
                   2520:        }
                   2521: 
                   2522:        if (error) {
                   2523:                *error = NULL;
                   2524:        }
                   2525: 
                   2526:        if (!index_php) {
                   2527:                index_php = "index.php";
                   2528:        }
                   2529: 
                   2530:        if (!web_index) {
                   2531:                web_index = "index.php";
                   2532:        }
                   2533: 
                   2534:        index_len = strlen(index_php);
                   2535:        web_len = strlen(web_index);
                   2536: 
                   2537:        if (index_len > 400) {
                   2538:                /* ridiculous size not allowed for index.php startup filename */
                   2539:                if (error) {
                   2540:                        spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
                   2541:                        return NULL;
                   2542:                }
                   2543:        }
                   2544: 
                   2545:        if (web_len > 400) {
                   2546:                /* ridiculous size not allowed for index.php startup filename */
                   2547:                if (error) {
                   2548:                        spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
                   2549:                        return NULL;
                   2550:                }
                   2551:        }
                   2552: 
                   2553:        phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
                   2554:        return stub;
                   2555: }
                   2556: /* }}} */
                   2557: 
                   2558: /**
                   2559:  * Save phar contents to disk
                   2560:  *
                   2561:  * user_stub contains either a string, or a resource pointer, if len is a negative length.
                   2562:  * user_stub and len should be both 0 if the default or existing stub should be used
                   2563:  */
                   2564: int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC) /* {{{ */
                   2565: {
                   2566:        char halt_stub[] = "__HALT_COMPILER();";
                   2567:        char *newstub, *tmp;
                   2568:        phar_entry_info *entry, *newentry;
                   2569:        int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
                   2570:        char *pos, has_dirs = 0;
                   2571:        char manifest[18], entry_buffer[24];
                   2572:        off_t manifest_ftell;
                   2573:        long offset;
                   2574:        size_t wrote;
                   2575:        php_uint32 manifest_len, mytime, loc, new_manifest_count;
                   2576:        php_uint32 newcrc32;
                   2577:        php_stream *file, *oldfile, *newfile, *stubfile;
                   2578:        php_stream_filter *filter;
                   2579:        php_serialize_data_t metadata_hash;
                   2580:        smart_str main_metadata_str = {0};
                   2581:        int free_user_stub, free_fp = 1, free_ufp = 1;
                   2582: 
                   2583:        if (phar->is_persistent) {
                   2584:                if (error) {
                   2585:                        spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
                   2586:                }
                   2587:                return EOF;
                   2588:        }
                   2589: 
                   2590:        if (error) {
                   2591:                *error = NULL;
                   2592:        }
                   2593: 
                   2594:        if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
                   2595:                return EOF;
                   2596:        }
                   2597: 
                   2598:        zend_hash_clean(&phar->virtual_dirs);
                   2599: 
                   2600:        if (phar->is_zip) {
                   2601:                return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
                   2602:        }
                   2603: 
                   2604:        if (phar->is_tar) {
                   2605:                return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
                   2606:        }
                   2607: 
                   2608:        if (PHAR_G(readonly)) {
                   2609:                return EOF;
                   2610:        }
                   2611: 
                   2612:        if (phar->fp && !phar->is_brandnew) {
                   2613:                oldfile = phar->fp;
                   2614:                closeoldfile = 0;
                   2615:                php_stream_rewind(oldfile);
                   2616:        } else {
                   2617:                oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
                   2618:                closeoldfile = oldfile != NULL;
                   2619:        }
                   2620:        newfile = php_stream_fopen_tmpfile();
                   2621:        if (!newfile) {
                   2622:                if (error) {
                   2623:                        spprintf(error, 0, "unable to create temporary file");
                   2624:                }
                   2625:                if (closeoldfile) {
                   2626:                        php_stream_close(oldfile);
                   2627:                }
                   2628:                return EOF;
                   2629:        }
                   2630: 
                   2631:        if (user_stub) {
                   2632:                if (len < 0) {
                   2633:                        /* resource passed in */
                   2634:                        if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
                   2635:                                if (closeoldfile) {
                   2636:                                        php_stream_close(oldfile);
                   2637:                                }
                   2638:                                php_stream_close(newfile);
                   2639:                                if (error) {
                   2640:                                        spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
                   2641:                                }
                   2642:                                return EOF;
                   2643:                        }
                   2644:                        if (len == -1) {
                   2645:                                len = PHP_STREAM_COPY_ALL;
                   2646:                        } else {
                   2647:                                len = -len;
                   2648:                        }
                   2649:                        user_stub = 0;
1.1.1.3 ! misho    2650: 
1.1       misho    2651:                        if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
                   2652:                                if (closeoldfile) {
                   2653:                                        php_stream_close(oldfile);
                   2654:                                }
                   2655:                                php_stream_close(newfile);
                   2656:                                if (error) {
                   2657:                                        spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
                   2658:                                }
                   2659:                                return EOF;
                   2660:                        }
                   2661:                        free_user_stub = 1;
                   2662:                } else {
                   2663:                        free_user_stub = 0;
                   2664:                }
                   2665:                tmp = estrndup(user_stub, len);
                   2666:                if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
                   2667:                        efree(tmp);
                   2668:                        if (closeoldfile) {
                   2669:                                php_stream_close(oldfile);
                   2670:                        }
                   2671:                        php_stream_close(newfile);
                   2672:                        if (error) {
                   2673:                                spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
                   2674:                        }
                   2675:                        if (free_user_stub) {
                   2676:                                efree(user_stub);
                   2677:                        }
                   2678:                        return EOF;
                   2679:                }
                   2680:                pos = user_stub + (pos - tmp);
                   2681:                efree(tmp);
                   2682:                len = pos - user_stub + 18;
                   2683:                if ((size_t)len != php_stream_write(newfile, user_stub, len)
                   2684:                ||                        5 != php_stream_write(newfile, " ?>\r\n", 5)) {
                   2685:                        if (closeoldfile) {
                   2686:                                php_stream_close(oldfile);
                   2687:                        }
                   2688:                        php_stream_close(newfile);
                   2689:                        if (error) {
                   2690:                                spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
                   2691:                        }
                   2692:                        if (free_user_stub) {
                   2693:                                efree(user_stub);
                   2694:                        }
                   2695:                        return EOF;
                   2696:                }
                   2697:                phar->halt_offset = len + 5;
                   2698:                if (free_user_stub) {
                   2699:                        efree(user_stub);
                   2700:                }
                   2701:        } else {
                   2702:                size_t written;
                   2703: 
                   2704:                if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
                   2705:                        phar_stream_copy_to_stream(oldfile, newfile, phar->halt_offset, &written);
                   2706:                        newstub = NULL;
                   2707:                } else {
                   2708:                        /* this is either a brand new phar or a default stub overwrite */
                   2709:                        newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
                   2710:                        written = php_stream_write(newfile, newstub, phar->halt_offset);
                   2711:                }
                   2712:                if (phar->halt_offset != written) {
                   2713:                        if (closeoldfile) {
                   2714:                                php_stream_close(oldfile);
                   2715:                        }
                   2716:                        php_stream_close(newfile);
                   2717:                        if (error) {
                   2718:                                if (newstub) {
                   2719:                                        spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
                   2720:                                } else {
                   2721:                                        spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
                   2722:                                }
                   2723:                        }
                   2724:                        if (newstub) {
                   2725:                                efree(newstub);
                   2726:                        }
                   2727:                        return EOF;
                   2728:                }
                   2729:                if (newstub) {
                   2730:                        efree(newstub);
                   2731:                }
                   2732:        }
                   2733:        manifest_ftell = php_stream_tell(newfile);
                   2734:        halt_offset = manifest_ftell;
                   2735: 
                   2736:        /* Check whether we can get rid of some of the deleted entries which are
                   2737:         * unused. However some might still be in use so even after this clean-up
                   2738:         * we need to skip entries marked is_deleted. */
                   2739:        zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
                   2740: 
                   2741:        /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
                   2742:        main_metadata_str.c = 0;
                   2743:        if (phar->metadata) {
                   2744:                PHP_VAR_SERIALIZE_INIT(metadata_hash);
                   2745:                php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
                   2746:                PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
                   2747:        } else {
                   2748:                main_metadata_str.len = 0;
                   2749:        }
                   2750:        new_manifest_count = 0;
                   2751:        offset = 0;
                   2752:        for (zend_hash_internal_pointer_reset(&phar->manifest);
                   2753:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
                   2754:                zend_hash_move_forward(&phar->manifest)) {
                   2755:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
                   2756:                        continue;
                   2757:                }
                   2758:                if (entry->cfp) {
                   2759:                        /* did we forget to get rid of cfp last time? */
                   2760:                        php_stream_close(entry->cfp);
                   2761:                        entry->cfp = 0;
                   2762:                }
                   2763:                if (entry->is_deleted || entry->is_mounted) {
                   2764:                        /* remove this from the new phar */
                   2765:                        continue;
                   2766:                }
                   2767:                if (!entry->is_modified && entry->fp_refcount) {
                   2768:                        /* open file pointers refer to this fp, do not free the stream */
                   2769:                        switch (entry->fp_type) {
                   2770:                                case PHAR_FP:
                   2771:                                        free_fp = 0;
                   2772:                                        break;
                   2773:                                case PHAR_UFP:
                   2774:                                        free_ufp = 0;
                   2775:                                default:
                   2776:                                        break;
                   2777:                        }
                   2778:                }
                   2779:                /* after excluding deleted files, calculate manifest size in bytes and number of entries */
                   2780:                ++new_manifest_count;
                   2781:                phar_add_virtual_dirs(phar, entry->filename, entry->filename_len TSRMLS_CC);
                   2782: 
                   2783:                if (entry->is_dir) {
                   2784:                        /* we use this to calculate API version, 1.1.1 is used for phars with directories */
                   2785:                        has_dirs = 1;
                   2786:                }
                   2787:                if (entry->metadata) {
                   2788:                        if (entry->metadata_str.c) {
                   2789:                                smart_str_free(&entry->metadata_str);
                   2790:                        }
                   2791:                        entry->metadata_str.c = 0;
                   2792:                        entry->metadata_str.len = 0;
                   2793:                        PHP_VAR_SERIALIZE_INIT(metadata_hash);
                   2794:                        php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
                   2795:                        PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
                   2796:                } else {
                   2797:                        if (entry->metadata_str.c) {
                   2798:                                smart_str_free(&entry->metadata_str);
                   2799:                        }
                   2800:                        entry->metadata_str.c = 0;
                   2801:                        entry->metadata_str.len = 0;
                   2802:                }
                   2803: 
                   2804:                /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
                   2805:                offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
                   2806: 
                   2807:                /* compress and rehash as necessary */
                   2808:                if ((oldfile && !entry->is_modified) || entry->is_dir) {
                   2809:                        if (entry->fp_type == PHAR_UFP) {
                   2810:                                /* reset so we can copy the compressed data over */
                   2811:                                entry->fp_type = PHAR_FP;
                   2812:                        }
                   2813:                        continue;
                   2814:                }
                   2815:                if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
                   2816:                        /* re-open internal file pointer just-in-time */
                   2817:                        newentry = phar_open_jit(phar, entry, error TSRMLS_CC);
                   2818:                        if (!newentry) {
                   2819:                                /* major problem re-opening, so we ignore this file and the error */
                   2820:                                efree(*error);
                   2821:                                *error = NULL;
                   2822:                                continue;
                   2823:                        }
                   2824:                        entry = newentry;
                   2825:                }
                   2826:                file = phar_get_efp(entry, 0 TSRMLS_CC);
                   2827:                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
                   2828:                        if (closeoldfile) {
                   2829:                                php_stream_close(oldfile);
                   2830:                        }
                   2831:                        php_stream_close(newfile);
                   2832:                        if (error) {
                   2833:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
                   2834:                        }
                   2835:                        return EOF;
                   2836:                }
                   2837:                newcrc32 = ~0;
                   2838:                mytime = entry->uncompressed_filesize;
                   2839:                for (loc = 0;loc < mytime; ++loc) {
                   2840:                        CRC32(newcrc32, php_stream_getc(file));
                   2841:                }
                   2842:                entry->crc32 = ~newcrc32;
                   2843:                entry->is_crc_checked = 1;
                   2844:                if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
                   2845:                        /* not compressed */
                   2846:                        entry->compressed_filesize = entry->uncompressed_filesize;
                   2847:                        continue;
                   2848:                }
                   2849:                filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
                   2850:                if (!filter) {
                   2851:                        if (closeoldfile) {
                   2852:                                php_stream_close(oldfile);
                   2853:                        }
                   2854:                        php_stream_close(newfile);
                   2855:                        if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
                   2856:                                if (error) {
                   2857:                                        spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
                   2858:                                }
                   2859:                        } else {
                   2860:                                if (error) {
                   2861:                                        spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
                   2862:                                }
                   2863:                        }
                   2864:                        return EOF;
                   2865:                }
                   2866: 
                   2867:                /* create new file that holds the compressed version */
                   2868:                /* work around inability to specify freedom in write and strictness
                   2869:                in read count */
                   2870:                entry->cfp = php_stream_fopen_tmpfile();
                   2871:                if (!entry->cfp) {
                   2872:                        if (error) {
                   2873:                                spprintf(error, 0, "unable to create temporary file");
                   2874:                        }
                   2875:                        if (closeoldfile) {
                   2876:                                php_stream_close(oldfile);
                   2877:                        }
                   2878:                        php_stream_close(newfile);
                   2879:                        return EOF;
                   2880:                }
                   2881:                php_stream_flush(file);
                   2882:                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
                   2883:                        if (closeoldfile) {
                   2884:                                php_stream_close(oldfile);
                   2885:                        }
                   2886:                        php_stream_close(newfile);
                   2887:                        if (error) {
                   2888:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
                   2889:                        }
                   2890:                        return EOF;
                   2891:                }
                   2892:                php_stream_filter_append((&entry->cfp->writefilters), filter);
                   2893:                if (SUCCESS != phar_stream_copy_to_stream(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
                   2894:                        if (closeoldfile) {
                   2895:                                php_stream_close(oldfile);
                   2896:                        }
                   2897:                        php_stream_close(newfile);
                   2898:                        if (error) {
                   2899:                                spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
                   2900:                        }
                   2901:                        return EOF;
                   2902:                }
                   2903:                php_stream_filter_flush(filter, 1);
                   2904:                php_stream_flush(entry->cfp);
                   2905:                php_stream_filter_remove(filter, 1 TSRMLS_CC);
                   2906:                php_stream_seek(entry->cfp, 0, SEEK_END);
                   2907:                entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
                   2908:                /* generate crc on compressed file */
                   2909:                php_stream_rewind(entry->cfp);
                   2910:                entry->old_flags = entry->flags;
                   2911:                entry->is_modified = 1;
                   2912:                global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
                   2913:        }
                   2914:        global_flags |= PHAR_HDR_SIGNATURE;
                   2915: 
                   2916:        /* write out manifest pre-header */
                   2917:        /*  4: manifest length
                   2918:         *  4: manifest entry count
                   2919:         *  2: phar version
                   2920:         *  4: phar global flags
                   2921:         *  4: alias length
                   2922:         *  ?: the alias itself
                   2923:         *  4: phar metadata length
                   2924:         *  ?: phar metadata
                   2925:         */
                   2926:        restore_alias_len = phar->alias_len;
                   2927:        if (phar->is_temporary_alias) {
                   2928:                phar->alias_len = 0;
                   2929:        }
                   2930: 
                   2931:        manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
                   2932:        phar_set_32(manifest, manifest_len);
                   2933:        phar_set_32(manifest+4, new_manifest_count);
                   2934:        if (has_dirs) {
                   2935:                *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
                   2936:                *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
                   2937:        } else {
                   2938:                *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
                   2939:                *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
                   2940:        }
                   2941:        phar_set_32(manifest+10, global_flags);
                   2942:        phar_set_32(manifest+14, phar->alias_len);
                   2943: 
                   2944:        /* write the manifest header */
                   2945:        if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
                   2946:        || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
                   2947: 
                   2948:                if (closeoldfile) {
                   2949:                        php_stream_close(oldfile);
                   2950:                }
                   2951: 
                   2952:                php_stream_close(newfile);
                   2953:                phar->alias_len = restore_alias_len;
                   2954: 
                   2955:                if (error) {
                   2956:                        spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
                   2957:                }
                   2958: 
                   2959:                return EOF;
                   2960:        }
                   2961: 
                   2962:        phar->alias_len = restore_alias_len;
                   2963: 
                   2964:        phar_set_32(manifest, main_metadata_str.len);
                   2965:        if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
                   2966:        && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
                   2967:                smart_str_free(&main_metadata_str);
                   2968: 
                   2969:                if (closeoldfile) {
                   2970:                        php_stream_close(oldfile);
                   2971:                }
                   2972: 
                   2973:                php_stream_close(newfile);
                   2974:                phar->alias_len = restore_alias_len;
                   2975: 
                   2976:                if (error) {
                   2977:                        spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
                   2978:                }
                   2979: 
                   2980:                return EOF;
                   2981:        }
                   2982:        smart_str_free(&main_metadata_str);
                   2983: 
                   2984:        /* re-calculate the manifest location to simplify later code */
                   2985:        manifest_ftell = php_stream_tell(newfile);
                   2986: 
                   2987:        /* now write the manifest */
                   2988:        for (zend_hash_internal_pointer_reset(&phar->manifest);
                   2989:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
                   2990:                zend_hash_move_forward(&phar->manifest)) {
                   2991: 
                   2992:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
                   2993:                        continue;
                   2994:                }
                   2995: 
                   2996:                if (entry->is_deleted || entry->is_mounted) {
                   2997:                        /* remove this from the new phar if deleted, ignore if mounted */
                   2998:                        continue;
                   2999:                }
                   3000: 
                   3001:                if (entry->is_dir) {
                   3002:                        /* add 1 for trailing slash */
                   3003:                        phar_set_32(entry_buffer, entry->filename_len + 1);
                   3004:                } else {
                   3005:                        phar_set_32(entry_buffer, entry->filename_len);
                   3006:                }
                   3007: 
                   3008:                if (4 != php_stream_write(newfile, entry_buffer, 4)
                   3009:                || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
                   3010:                || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
                   3011:                        if (closeoldfile) {
                   3012:                                php_stream_close(oldfile);
                   3013:                        }
                   3014:                        php_stream_close(newfile);
                   3015:                        if (error) {
                   3016:                                if (entry->is_dir) {
                   3017:                                        spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
                   3018:                                } else {
                   3019:                                        spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
                   3020:                                }
                   3021:                        }
                   3022:                        return EOF;
                   3023:                }
                   3024: 
                   3025:                /* set the manifest meta-data:
                   3026:                        4: uncompressed filesize
                   3027:                        4: creation timestamp
                   3028:                        4: compressed filesize
                   3029:                        4: crc32
                   3030:                        4: flags
                   3031:                        4: metadata-len
                   3032:                        +: metadata
                   3033:                */
                   3034:                mytime = time(NULL);
                   3035:                phar_set_32(entry_buffer, entry->uncompressed_filesize);
                   3036:                phar_set_32(entry_buffer+4, mytime);
                   3037:                phar_set_32(entry_buffer+8, entry->compressed_filesize);
                   3038:                phar_set_32(entry_buffer+12, entry->crc32);
                   3039:                phar_set_32(entry_buffer+16, entry->flags);
                   3040:                phar_set_32(entry_buffer+20, entry->metadata_str.len);
                   3041: 
                   3042:                if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
                   3043:                || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
                   3044:                        if (closeoldfile) {
                   3045:                                php_stream_close(oldfile);
                   3046:                        }
                   3047: 
                   3048:                        php_stream_close(newfile);
                   3049: 
                   3050:                        if (error) {
                   3051:                                spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
                   3052:                        }
                   3053: 
                   3054:                        return EOF;
                   3055:                }
                   3056:        }
                   3057: 
                   3058:        /* now copy the actual file data to the new phar */
                   3059:        offset = php_stream_tell(newfile);
                   3060:        for (zend_hash_internal_pointer_reset(&phar->manifest);
                   3061:                zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
                   3062:                zend_hash_move_forward(&phar->manifest)) {
                   3063: 
                   3064:                if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
                   3065:                        continue;
                   3066:                }
                   3067: 
                   3068:                if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
                   3069:                        continue;
                   3070:                }
                   3071: 
                   3072:                if (entry->cfp) {
                   3073:                        file = entry->cfp;
                   3074:                        php_stream_rewind(file);
                   3075:                } else {
                   3076:                        file = phar_get_efp(entry, 0 TSRMLS_CC);
                   3077:                        if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
                   3078:                                if (closeoldfile) {
                   3079:                                        php_stream_close(oldfile);
                   3080:                                }
                   3081:                                php_stream_close(newfile);
                   3082:                                if (error) {
                   3083:                                        spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
                   3084:                                }
                   3085:                                return EOF;
                   3086:                        }
                   3087:                }
                   3088: 
                   3089:                if (!file) {
                   3090:                        if (closeoldfile) {
                   3091:                                php_stream_close(oldfile);
                   3092:                        }
                   3093:                        php_stream_close(newfile);
                   3094:                        if (error) {
                   3095:                                spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
                   3096:                        }
                   3097:                        return EOF;
                   3098:                }
                   3099: 
                   3100:                /* this will have changed for all files that have either changed compression or been modified */
                   3101:                entry->offset = entry->offset_abs = offset;
                   3102:                offset += entry->compressed_filesize;
                   3103:                if (phar_stream_copy_to_stream(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
                   3104:                        if (closeoldfile) {
                   3105:                                php_stream_close(oldfile);
                   3106:                        }
                   3107: 
                   3108:                        php_stream_close(newfile);
                   3109: 
                   3110:                        if (error) {
                   3111:                                spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
                   3112:                        }
                   3113: 
                   3114:                        return EOF;
                   3115:                }
                   3116: 
                   3117:                entry->is_modified = 0;
                   3118: 
                   3119:                if (entry->cfp) {
                   3120:                        php_stream_close(entry->cfp);
                   3121:                        entry->cfp = NULL;
                   3122:                }
                   3123: 
                   3124:                if (entry->fp_type == PHAR_MOD) {
                   3125:                        /* 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 */
                   3126:                        if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
                   3127:                                php_stream_close(entry->fp);
                   3128:                        }
                   3129: 
                   3130:                        entry->fp = NULL;
                   3131:                        entry->fp_type = PHAR_FP;
                   3132:                } else if (entry->fp_type == PHAR_UFP) {
                   3133:                        entry->fp_type = PHAR_FP;
                   3134:                }
                   3135:        }
                   3136: 
                   3137:        /* append signature */
                   3138:        if (global_flags & PHAR_HDR_SIGNATURE) {
                   3139:                char sig_buf[4];
                   3140: 
                   3141:                php_stream_rewind(newfile);
                   3142: 
                   3143:                if (phar->signature) {
                   3144:                        efree(phar->signature);
                   3145:                        phar->signature = NULL;
                   3146:                }
                   3147: 
                   3148:                switch(phar->sig_flags) {
                   3149: #ifndef PHAR_HASH_OK
                   3150:                        case PHAR_SIG_SHA512:
                   3151:                        case PHAR_SIG_SHA256:
                   3152:                                if (closeoldfile) {
                   3153:                                        php_stream_close(oldfile);
                   3154:                                }
                   3155:                                php_stream_close(newfile);
                   3156:                                if (error) {
                   3157:                                        spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
                   3158:                                }
                   3159:                                return EOF;
                   3160: #endif
                   3161:                        default: {
                   3162:                                char *digest = NULL;
                   3163:                                int digest_len;
                   3164: 
                   3165:                                if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
                   3166:                                        if (error) {
                   3167:                                                char *save = *error;
                   3168:                                                spprintf(error, 0, "phar error: unable to write signature: %s", save);
                   3169:                                                efree(save);
                   3170:                                        }
                   3171:                                        if (digest) {
                   3172:                                                efree(digest);
                   3173:                                        }
                   3174:                                        if (closeoldfile) {
                   3175:                                                php_stream_close(oldfile);
                   3176:                                        }
                   3177:                                        php_stream_close(newfile);
                   3178:                                        return EOF;
                   3179:                                }
                   3180: 
                   3181:                                php_stream_write(newfile, digest, digest_len);
                   3182:                                efree(digest);
                   3183:                                if (phar->sig_flags == PHAR_SIG_OPENSSL) {
                   3184:                                        phar_set_32(sig_buf, digest_len);
                   3185:                                        php_stream_write(newfile, sig_buf, 4);
                   3186:                                }
                   3187:                                break;
                   3188:                        }
                   3189:                }
                   3190:                phar_set_32(sig_buf, phar->sig_flags);
                   3191:                php_stream_write(newfile, sig_buf, 4);
                   3192:                php_stream_write(newfile, "GBMB", 4);
                   3193:        }
                   3194: 
                   3195:        /* finally, close the temp file, rename the original phar,
                   3196:           move the temp to the old phar, unlink the old phar, and reload it into memory
                   3197:        */
                   3198:        if (phar->fp && free_fp) {
                   3199:                php_stream_close(phar->fp);
                   3200:        }
                   3201: 
                   3202:        if (phar->ufp) {
                   3203:                if (free_ufp) {
                   3204:                        php_stream_close(phar->ufp);
                   3205:                }
                   3206:                phar->ufp = NULL;
                   3207:        }
                   3208: 
                   3209:        if (closeoldfile) {
                   3210:                php_stream_close(oldfile);
                   3211:        }
                   3212: 
                   3213:        phar->internal_file_start = halt_offset + manifest_len + 4;
                   3214:        phar->halt_offset = halt_offset;
                   3215:        phar->is_brandnew = 0;
                   3216: 
                   3217:        php_stream_rewind(newfile);
                   3218: 
                   3219:        if (phar->donotflush) {
                   3220:                /* deferred flush */
                   3221:                phar->fp = newfile;
                   3222:        } else {
                   3223:                phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
                   3224:                if (!phar->fp) {
                   3225:                        phar->fp = newfile;
                   3226:                        if (error) {
                   3227:                                spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
                   3228:                        }
                   3229:                        return EOF;
                   3230:                }
                   3231: 
                   3232:                if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
                   3233:                        /* to properly compress, we have to tell zlib to add a zlib header */
                   3234:                        zval filterparams;
                   3235: 
                   3236:                        array_init(&filterparams);
                   3237:                        add_assoc_long(&filterparams, "window", MAX_WBITS+16);
                   3238:                        filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
                   3239:                        zval_dtor(&filterparams);
                   3240: 
                   3241:                        if (!filter) {
                   3242:                                if (error) {
                   3243:                                        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);
                   3244:                                }
                   3245:                                return EOF;
                   3246:                        }
                   3247: 
                   3248:                        php_stream_filter_append(&phar->fp->writefilters, filter);
                   3249:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   3250:                        php_stream_filter_flush(filter, 1);
                   3251:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
                   3252:                        php_stream_close(phar->fp);
                   3253:                        /* use the temp stream as our base */
                   3254:                        phar->fp = newfile;
                   3255:                } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
                   3256:                        filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
                   3257:                        php_stream_filter_append(&phar->fp->writefilters, filter);
                   3258:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   3259:                        php_stream_filter_flush(filter, 1);
                   3260:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
                   3261:                        php_stream_close(phar->fp);
                   3262:                        /* use the temp stream as our base */
                   3263:                        phar->fp = newfile;
                   3264:                } else {
                   3265:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   3266:                        /* we could also reopen the file in "rb" mode but there is no need for that */
                   3267:                        php_stream_close(newfile);
                   3268:                }
                   3269:        }
                   3270: 
                   3271:        if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
                   3272:                if (error) {
                   3273:                        spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
                   3274:                }
                   3275:                return EOF;
                   3276:        }
                   3277: 
                   3278:        return EOF;
                   3279: }
                   3280: /* }}} */
                   3281: 
                   3282: #ifdef COMPILE_DL_PHAR
                   3283: ZEND_GET_MODULE(phar)
                   3284: #endif
                   3285: 
                   3286: /* {{{ phar_functions[]
                   3287:  *
                   3288:  * Every user visible function must have an entry in phar_functions[].
                   3289:  */
                   3290: zend_function_entry phar_functions[] = {
                   3291:        PHP_FE_END
                   3292: };
                   3293: /* }}}*/
                   3294: 
                   3295: static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
                   3296: {
                   3297:        return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
                   3298: }
                   3299: /* }}} */
                   3300: 
                   3301: #if PHP_VERSION_ID >= 50300
                   3302: static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
                   3303: {
                   3304:        return ((phar_archive_data*)handle)->halt_offset + 32;
                   3305: } /* }}} */
                   3306: 
                   3307: #else /* PHP_VERSION_ID */
                   3308: 
                   3309: static long phar_stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
                   3310: {
                   3311:        return (long)php_stream_tell(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC));
                   3312: }
                   3313: /* }}} */
                   3314: #endif
                   3315: 
                   3316: zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
                   3317: #if PHP_VERSION_ID >= 50300
                   3318: #define phar_orig_zend_open zend_stream_open_function
                   3319: static char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
                   3320: {
                   3321:        return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
                   3322: }
                   3323: #else
                   3324: int (*phar_orig_zend_open)(const char *filename, zend_file_handle *handle TSRMLS_DC);
                   3325: #endif
                   3326: 
                   3327: static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
                   3328: {
                   3329:        zend_op_array *res;
                   3330:        char *name = NULL;
                   3331:        int failed;
                   3332:        phar_archive_data *phar;
                   3333: 
                   3334:        if (!file_handle || !file_handle->filename) {
                   3335:                return phar_orig_compile_file(file_handle, type TSRMLS_CC);
                   3336:        }
                   3337:        if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
1.1.1.2   misho    3338:                if (SUCCESS == phar_open_from_filename((char*)file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
1.1       misho    3339:                        if (phar->is_zip || phar->is_tar) {
                   3340:                                zend_file_handle f = *file_handle;
                   3341: 
                   3342:                                /* zip or tar-based phar */
                   3343:                                spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
                   3344:                                if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
                   3345:                                        efree(name);
                   3346:                                        name = NULL;
                   3347:                                        file_handle->filename = f.filename;
                   3348:                                        if (file_handle->opened_path) {
                   3349:                                                efree(file_handle->opened_path);
                   3350:                                        }
                   3351:                                        file_handle->opened_path = f.opened_path;
                   3352:                                        file_handle->free_filename = f.free_filename;
                   3353:                                } else {
                   3354:                                        *file_handle = f;
                   3355:                                }
                   3356:                        } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
                   3357:                                /* compressed phar */
                   3358: #if PHP_VERSION_ID >= 50300
                   3359:                                file_handle->type = ZEND_HANDLE_STREAM;
                   3360:                                /* we do our own reading directly from the phar, don't change the next line */
                   3361:                                file_handle->handle.stream.handle  = phar;
                   3362:                                file_handle->handle.stream.reader  = phar_zend_stream_reader;
                   3363:                                file_handle->handle.stream.closer  = NULL;
                   3364:                                file_handle->handle.stream.fsizer  = phar_zend_stream_fsizer;
                   3365:                                file_handle->handle.stream.isatty  = 0;
                   3366:                                phar->is_persistent ?
                   3367:                                        php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
                   3368:                                        php_stream_rewind(phar->fp);
                   3369:                                memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
                   3370: #else /* PHP_VERSION_ID */
                   3371:                                file_handle->type = ZEND_HANDLE_STREAM;
                   3372:                                /* we do our own reading directly from the phar, don't change the next line */
                   3373:                                file_handle->handle.stream.handle = phar;
                   3374:                                file_handle->handle.stream.reader = phar_zend_stream_reader;
                   3375:                                file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */
                   3376:                                file_handle->handle.stream.fteller = phar_stream_fteller_for_zend;
                   3377:                                file_handle->handle.stream.interactive = 0;
                   3378:                                phar->is_persistent ?
                   3379:                                        php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
                   3380:                                        php_stream_rewind(phar->fp);
                   3381: #endif
                   3382:                        }
                   3383:                }
                   3384:        }
                   3385: 
                   3386:        zend_try {
                   3387:                failed = 0;
                   3388:                res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
                   3389:        } zend_catch {
                   3390:                failed = 1;
                   3391:                res = NULL;
                   3392:        } zend_end_try();
                   3393: 
                   3394:        if (name) {
                   3395:                efree(name);
                   3396:        }
                   3397: 
                   3398:        if (failed) {
                   3399:                zend_bailout();
                   3400:        }
                   3401: 
                   3402:        return res;
                   3403: }
                   3404: /* }}} */
                   3405: 
                   3406: #if PHP_VERSION_ID < 50300
                   3407: int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
                   3408: {
                   3409:        char *arch, *entry;
                   3410:        int arch_len, entry_len;
                   3411: 
                   3412:        /* this code is obsoleted in php 5.3 */
                   3413:        entry = (char *) filename;
                   3414:        if (!IS_ABSOLUTE_PATH(entry, strlen(entry)) && !strstr(entry, "://")) {
                   3415:                phar_archive_data **pphar = NULL;
                   3416:                char *fname;
                   3417:                int fname_len;
                   3418: 
1.1.1.2   misho    3419:                fname = (char*)zend_get_executed_filename(TSRMLS_C);
1.1       misho    3420:                fname_len = strlen(fname);
                   3421: 
                   3422:                if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
                   3423:                        if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
                   3424:                                zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
                   3425:                                if (!pphar && PHAR_G(manifest_cached)) {
                   3426:                                        zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
                   3427:                                }
                   3428:                                efree(arch);
                   3429:                                efree(entry);
                   3430:                        }
                   3431:                }
                   3432: 
                   3433:                /* retrieving an include within the current directory, so use this if possible */
                   3434:                if (!(entry = phar_find_in_include_path((char *) filename, strlen(filename), NULL TSRMLS_CC))) {
                   3435:                        /* this file is not in the phar, use the original path */
                   3436:                        goto skip_phar;
                   3437:                }
                   3438: 
                   3439:                if (SUCCESS == phar_orig_zend_open(entry, handle TSRMLS_CC)) {
                   3440:                        if (!handle->opened_path) {
                   3441:                                handle->opened_path = entry;
                   3442:                        }
                   3443:                        if (entry != filename) {
                   3444:                                handle->free_filename = 1;
                   3445:                        }
                   3446:                        return SUCCESS;
                   3447:                }
                   3448: 
                   3449:                if (entry != filename) {
                   3450:                        efree(entry);
                   3451:                }
                   3452: 
                   3453:                return FAILURE;
                   3454:        }
                   3455: skip_phar:
                   3456:        return phar_orig_zend_open(filename, handle TSRMLS_CC);
                   3457: }
                   3458: /* }}} */
                   3459: #endif
                   3460: typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
                   3461: typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
                   3462: 
                   3463: PHP_GINIT_FUNCTION(phar) /* {{{ */
                   3464: {
                   3465:        phar_mime_type mime;
                   3466: 
                   3467:        memset(phar_globals, 0, sizeof(zend_phar_globals));
                   3468:        phar_globals->readonly = 1;
                   3469: 
                   3470:        zend_hash_init(&phar_globals->mime_types, 0, NULL, NULL, 1);
                   3471: 
                   3472: #define PHAR_SET_MIME(mimetype, ret, fileext) \
                   3473:                mime.mime = mimetype; \
                   3474:                mime.len = sizeof((mimetype))+1; \
                   3475:                mime.type = ret; \
                   3476:                zend_hash_add(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
                   3477: 
                   3478:        PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
                   3479:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
                   3480:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
                   3481:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
                   3482:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
                   3483:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
                   3484:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
                   3485:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
                   3486:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
                   3487:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
                   3488:        PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
                   3489:        PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
                   3490:        PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
                   3491:        PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
                   3492:        PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
                   3493:        PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
                   3494:        PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
                   3495:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
                   3496:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
                   3497:        PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
                   3498:        PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
                   3499:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
                   3500:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
                   3501:        PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
                   3502:        PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
                   3503:        PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
                   3504:        PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
                   3505:        PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
                   3506:        PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
                   3507:        PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
                   3508:        PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
                   3509:        PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
                   3510:        PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
                   3511:        PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
                   3512:        PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
                   3513:        PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
                   3514:        PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
                   3515:        PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
                   3516:        PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
                   3517:        PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
                   3518: 
                   3519:        phar_restore_orig_functions(TSRMLS_C);
                   3520: }
                   3521: /* }}} */
                   3522: 
                   3523: PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
                   3524: {
                   3525:        zend_hash_destroy(&phar_globals->mime_types);
                   3526: }
                   3527: /* }}} */
                   3528: 
                   3529: PHP_MINIT_FUNCTION(phar) /* {{{ */
                   3530: {
                   3531:        REGISTER_INI_ENTRIES();
                   3532: 
                   3533:        phar_orig_compile_file = zend_compile_file;
                   3534:        zend_compile_file = phar_compile_file;
                   3535: 
                   3536: #if PHP_VERSION_ID >= 50300
                   3537:        phar_save_resolve_path = zend_resolve_path;
                   3538:        zend_resolve_path = phar_resolve_path;
                   3539: #else
                   3540:        phar_orig_zend_open = zend_stream_open_function;
                   3541:        zend_stream_open_function = phar_zend_open;
                   3542: #endif
                   3543: 
                   3544:        phar_object_init(TSRMLS_C);
                   3545: 
                   3546:        phar_intercept_functions_init(TSRMLS_C);
                   3547:        phar_save_orig_functions(TSRMLS_C);
                   3548: 
                   3549:        return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
                   3550: }
                   3551: /* }}} */
                   3552: 
                   3553: PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
                   3554: {
                   3555:        php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
                   3556: 
                   3557:        phar_intercept_functions_shutdown(TSRMLS_C);
                   3558: 
                   3559:        if (zend_compile_file == phar_compile_file) {
                   3560:                zend_compile_file = phar_orig_compile_file;
                   3561:        }
                   3562: 
                   3563: #if PHP_VERSION_ID < 50300
                   3564:        if (zend_stream_open_function == phar_zend_open) {
                   3565:                zend_stream_open_function = phar_orig_zend_open;
                   3566:        }
                   3567: #endif
                   3568:        if (PHAR_G(manifest_cached)) {
                   3569:                zend_hash_destroy(&(cached_phars));
                   3570:                zend_hash_destroy(&(cached_alias));
                   3571:        }
                   3572: 
                   3573:        return SUCCESS;
                   3574: }
                   3575: /* }}} */
                   3576: 
                   3577: void phar_request_initialize(TSRMLS_D) /* {{{ */
                   3578: {
                   3579:        if (!PHAR_GLOBALS->request_init)
                   3580:        {
                   3581:                PHAR_G(last_phar) = NULL;
                   3582:                PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
                   3583:                PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
                   3584:                PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
                   3585:                PHAR_GLOBALS->request_init = 1;
                   3586:                PHAR_GLOBALS->request_ends = 0;
                   3587:                PHAR_GLOBALS->request_done = 0;
                   3588:                zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data,  0);
                   3589:                zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL,  0);
                   3590:                zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
                   3591: 
                   3592:                if (PHAR_G(manifest_cached)) {
                   3593:                        phar_archive_data **pphar;
                   3594:                        phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
                   3595: 
                   3596:                        for (zend_hash_internal_pointer_reset(&cached_phars);
                   3597:                        zend_hash_get_current_data(&cached_phars, (void **)&pphar) == SUCCESS;
                   3598:                        zend_hash_move_forward(&cached_phars)) {
                   3599:                                stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
                   3600:                        }
                   3601: 
                   3602:                        PHAR_GLOBALS->cached_fp = stuff;
                   3603:                }
                   3604: 
                   3605:                PHAR_GLOBALS->phar_SERVER_mung_list = 0;
                   3606:                PHAR_G(cwd) = NULL;
                   3607:                PHAR_G(cwd_len) = 0;
                   3608:                PHAR_G(cwd_init) = 0;
                   3609:        }
                   3610: }
                   3611: /* }}} */
                   3612: 
                   3613: PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
                   3614: {
                   3615:        int i;
                   3616: 
                   3617:        PHAR_GLOBALS->request_ends = 1;
                   3618: 
                   3619:        if (PHAR_GLOBALS->request_init)
                   3620:        {
                   3621:                phar_release_functions(TSRMLS_C);
                   3622:                zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
                   3623:                PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
                   3624:                zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
                   3625:                PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
                   3626:                zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
                   3627:                PHAR_GLOBALS->phar_persist_map.arBuckets = NULL;
                   3628:                PHAR_GLOBALS->phar_SERVER_mung_list = 0;
                   3629: 
                   3630:                if (PHAR_GLOBALS->cached_fp) {
                   3631:                        for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
                   3632:                                if (PHAR_GLOBALS->cached_fp[i].fp) {
                   3633:                                        php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
                   3634:                                }
                   3635:                                if (PHAR_GLOBALS->cached_fp[i].ufp) {
                   3636:                                        php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
                   3637:                                }
                   3638:                                efree(PHAR_GLOBALS->cached_fp[i].manifest);
                   3639:                        }
                   3640:                        efree(PHAR_GLOBALS->cached_fp);
                   3641:                        PHAR_GLOBALS->cached_fp = 0;
                   3642:                }
                   3643: 
                   3644:                PHAR_GLOBALS->request_init = 0;
                   3645: 
                   3646:                if (PHAR_G(cwd)) {
                   3647:                        efree(PHAR_G(cwd));
                   3648:                }
                   3649: 
                   3650:                PHAR_G(cwd) = NULL;
                   3651:                PHAR_G(cwd_len) = 0;
                   3652:                PHAR_G(cwd_init) = 0;
                   3653:        }
                   3654: 
                   3655:        PHAR_GLOBALS->request_done = 1;
                   3656:        return SUCCESS;
                   3657: }
                   3658: /* }}} */
                   3659: 
                   3660: PHP_MINFO_FUNCTION(phar) /* {{{ */
                   3661: {
                   3662:        phar_request_initialize(TSRMLS_C);
                   3663:        php_info_print_table_start();
                   3664:        php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
                   3665:        php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
                   3666:        php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
1.1.1.3 ! misho    3667:        php_info_print_table_row(2, "SVN revision", "$Id: c5042cc34acebcc0926625b57dff03deebbe6472 $");
1.1       misho    3668:        php_info_print_table_row(2, "Phar-based phar archives", "enabled");
                   3669:        php_info_print_table_row(2, "Tar-based phar archives", "enabled");
                   3670:        php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
                   3671: 
                   3672:        if (PHAR_G(has_zlib)) {
                   3673:                php_info_print_table_row(2, "gzip compression", "enabled");
                   3674:        } else {
                   3675:                php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
                   3676:        }
                   3677: 
                   3678:        if (PHAR_G(has_bz2)) {
                   3679:                php_info_print_table_row(2, "bzip2 compression", "enabled");
                   3680:        } else {
                   3681:                php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
                   3682:        }
                   3683: #ifdef PHAR_HAVE_OPENSSL
                   3684:        php_info_print_table_row(2, "Native OpenSSL support", "enabled");
                   3685: #else
                   3686:        if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
                   3687:                php_info_print_table_row(2, "OpenSSL support", "enabled");
                   3688:        } else {
                   3689:                php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
                   3690:        }
                   3691: #endif
                   3692:        php_info_print_table_end();
                   3693: 
                   3694:        php_info_print_box_start(0);
                   3695:        PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
                   3696:        PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
                   3697:        PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
                   3698:        PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
                   3699:        PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
                   3700:        php_info_print_box_end();
                   3701: 
                   3702:        DISPLAY_INI_ENTRIES();
                   3703: }
                   3704: /* }}} */
                   3705: 
                   3706: /* {{{ phar_module_entry
                   3707:  */
                   3708: static const zend_module_dep phar_deps[] = {
                   3709:        ZEND_MOD_OPTIONAL("apc")
                   3710:        ZEND_MOD_OPTIONAL("bz2")
                   3711:        ZEND_MOD_OPTIONAL("openssl")
                   3712:        ZEND_MOD_OPTIONAL("zlib")
                   3713:        ZEND_MOD_OPTIONAL("standard")
                   3714: #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
                   3715:        ZEND_MOD_REQUIRED("hash")
                   3716: #endif
                   3717: #if HAVE_SPL
                   3718:        ZEND_MOD_REQUIRED("spl")
                   3719: #endif
                   3720:        ZEND_MOD_END
                   3721: };
                   3722: 
                   3723: zend_module_entry phar_module_entry = {
                   3724:        STANDARD_MODULE_HEADER_EX, NULL,
                   3725:        phar_deps,
                   3726:        "Phar",
                   3727:        phar_functions,
                   3728:        PHP_MINIT(phar),
                   3729:        PHP_MSHUTDOWN(phar),
                   3730:        NULL,
                   3731:        PHP_RSHUTDOWN(phar),
                   3732:        PHP_MINFO(phar),
                   3733:        PHP_PHAR_VERSION,
                   3734:        PHP_MODULE_GLOBALS(phar),   /* globals descriptor */
                   3735:        PHP_GINIT(phar),            /* globals ctor */
                   3736:        PHP_GSHUTDOWN(phar),        /* globals dtor */
                   3737:        NULL,                       /* post deactivate */
                   3738:        STANDARD_MODULE_PROPERTIES_EX
                   3739: };
                   3740: /* }}} */
                   3741: 
                   3742: /*
                   3743:  * Local variables:
                   3744:  * tab-width: 4
                   3745:  * c-basic-offset: 4
                   3746:  * End:
                   3747:  * vim600: noet sw=4 ts=4 fdm=marker
                   3748:  * vim<600: noet sw=4 ts=4
                   3749:  */

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