Annotation of embedaddon/php/ext/phar/tar.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | TAR archive support for Phar                                         |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 2005-2012 The PHP Group                                |
                      6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt.                                 |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Authors: Dmitry Stogov <dmitry@zend.com>                             |
                     16:   |          Gregory Beaver <cellog@php.net>                             |
                     17:   +----------------------------------------------------------------------+
                     18: */
                     19: 
                     20: #include "phar_internal.h"
                     21: 
                     22: static php_uint32 phar_tar_number(char *buf, int len) /* {{{ */
                     23: {
                     24:        php_uint32 num = 0;
                     25:        int i = 0;
                     26: 
                     27:        while (i < len && buf[i] == ' ') {
                     28:                ++i;
                     29:        }
                     30: 
                     31:        while (i < len && buf[i] >= '0' && buf[i] <= '7') {
                     32:                num = num * 8 + (buf[i] - '0');
                     33:                ++i;
                     34:        }
                     35: 
                     36:        return num;
                     37: }
                     38: /* }}} */
                     39: 
                     40: /* adapted from format_octal() in libarchive
                     41:  * 
                     42:  * Copyright (c) 2003-2009 Tim Kientzle
                     43:  * All rights reserved.
                     44:  *
                     45:  * Redistribution and use in source and binary forms, with or without
                     46:  * modification, are permitted provided that the following conditions
                     47:  * are met:
                     48:  * 1. Redistributions of source code must retain the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer.
                     50:  * 2. Redistributions in binary form must reproduce the above copyright
                     51:  *    notice, this list of conditions and the following disclaimer in the
                     52:  *    documentation and/or other materials provided with the distribution.
                     53:  *
                     54:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
                     55:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     56:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     57:  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
                     58:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     59:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     60:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     61:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     62:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     63:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     64:  */
                     65: static int phar_tar_octal(char *buf, php_uint32 val, int len) /* {{{ */
                     66: {
                     67:        char *p = buf;
                     68:        int s = len;
                     69: 
                     70:        p += len;               /* Start at the end and work backwards. */
                     71:        while (s-- > 0) {
                     72:                *--p = (char)('0' + (val & 7));
                     73:                val >>= 3;
                     74:        }
                     75: 
                     76:        if (val == 0)
                     77:                return SUCCESS;
                     78: 
                     79:        /* If it overflowed, fill field with max value. */
                     80:        while (len-- > 0)
                     81:                *p++ = '7';
                     82: 
                     83:        return FAILURE;
                     84: }
                     85: /* }}} */
                     86: 
                     87: static php_uint32 phar_tar_checksum(char *buf, int len) /* {{{ */
                     88: {
                     89:        php_uint32 sum = 0;
                     90:        char *end = buf + len;
                     91: 
                     92:        while (buf != end) {
                     93:                sum += (unsigned char)*buf;
                     94:                ++buf;
                     95:        }
                     96:        return sum;
                     97: }
                     98: /* }}} */
                     99: 
                    100: int phar_is_tar(char *buf, char *fname) /* {{{ */
                    101: {
                    102:        tar_header *header = (tar_header *) buf;
                    103:        php_uint32 checksum = phar_tar_number(header->checksum, sizeof(header->checksum));
                    104:        php_uint32 ret;
                    105:        char save[sizeof(header->checksum)];
                    106: 
                    107:        /* assume that the first filename in a tar won't begin with <?php */
                    108:        if (!strncmp(buf, "<?php", sizeof("<?php")-1)) {
                    109:                return 0;
                    110:        }
                    111: 
                    112:        memcpy(save, header->checksum, sizeof(header->checksum));
                    113:        memset(header->checksum, ' ', sizeof(header->checksum));
                    114:        ret = (checksum == phar_tar_checksum(buf, 512));
                    115:        memcpy(header->checksum, save, sizeof(header->checksum));
                    116:        if (!ret && strstr(fname, ".tar")) {
                    117:                /* probably a corrupted tar - so we will pretend it is one */
                    118:                return 1;
                    119:        }
                    120:        return ret;
                    121: }
                    122: /* }}} */
                    123: 
                    124: int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
                    125: {
                    126:        phar_archive_data *phar;
                    127:        int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC);
                    128: 
                    129:        if (FAILURE == ret) {
                    130:                return FAILURE;
                    131:        }
                    132: 
                    133:        if (pphar) {
                    134:                *pphar = phar;
                    135:        }
                    136: 
                    137:        phar->is_data = is_data;
                    138: 
                    139:        if (phar->is_tar) {
                    140:                return ret;
                    141:        }
                    142: 
                    143:        if (phar->is_brandnew) {
                    144:                phar->is_tar = 1;
                    145:                phar->is_zip = 0;
                    146:                phar->internal_file_start = 0;
                    147:                return SUCCESS;
                    148:        }
                    149: 
                    150:        /* we've reached here - the phar exists and is a regular phar */
                    151:        if (error) {
                    152:                spprintf(error, 4096, "phar tar error: \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar", fname);
                    153:        }
                    154:        return FAILURE;
                    155: }
                    156: /* }}} */
                    157: 
                    158: static int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */
                    159: {
                    160:        char *metadata;
                    161:        size_t save = php_stream_tell(fp), read;
                    162:        phar_entry_info *mentry;
                    163: 
                    164:        metadata = (char *) emalloc(entry->uncompressed_filesize + 1);
                    165: 
                    166:        read = php_stream_read(fp, metadata, entry->uncompressed_filesize);
                    167:        if (read != entry->uncompressed_filesize) {
                    168:                efree(metadata);
                    169:                php_stream_seek(fp, save, SEEK_SET);
                    170:                return FAILURE;
                    171:        }
                    172: 
                    173:        if (phar_parse_metadata(&metadata, &entry->metadata, entry->uncompressed_filesize TSRMLS_CC) == FAILURE) {
                    174:                /* if not valid serialized data, it is a regular string */
                    175:                efree(metadata);
                    176:                php_stream_seek(fp, save, SEEK_SET);
                    177:                return FAILURE;
                    178:        }
                    179: 
                    180:        if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 && !memcmp(entry->filename, ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1)) {
                    181:                entry->phar->metadata = entry->metadata;
                    182:                entry->metadata = NULL;
                    183:        } else if (entry->filename_len >= sizeof(".phar/.metadata/") + sizeof("/.metadata.bin") - 1 && SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->filename + sizeof(".phar/.metadata/") - 1, entry->filename_len - (sizeof("/.metadata.bin") - 1 + sizeof(".phar/.metadata/") - 1), (void *)&mentry)) {
                    184:                /* transfer this metadata to the entry it refers */
                    185:                mentry->metadata = entry->metadata;
                    186:                entry->metadata = NULL;
                    187:        }
                    188: 
                    189:        efree(metadata);
                    190:        php_stream_seek(fp, save, SEEK_SET);
                    191:        return SUCCESS;
                    192: }
                    193: /* }}} */
                    194: 
                    195: int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, int is_data, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
                    196: {
                    197:        char buf[512], *actual_alias = NULL, *p;
                    198:        phar_entry_info entry = {0};
                    199:        size_t pos = 0, read, totalsize;
                    200:        tar_header *hdr;
                    201:        php_uint32 sum1, sum2, size, old;
                    202:        phar_archive_data *myphar, **actual;
                    203:        int last_was_longlink = 0;
                    204: 
                    205:        if (error) {
                    206:                *error = NULL;
                    207:        }
                    208: 
                    209:        php_stream_seek(fp, 0, SEEK_END);
                    210:        totalsize = php_stream_tell(fp);
                    211:        php_stream_seek(fp, 0, SEEK_SET);
                    212:        read = php_stream_read(fp, buf, sizeof(buf));
                    213: 
                    214:        if (read != sizeof(buf)) {
                    215:                if (error) {
                    216:                        spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname);
                    217:                }
                    218:                php_stream_close(fp);
                    219:                return FAILURE;
                    220:        }
                    221: 
                    222:        hdr = (tar_header*)buf;
                    223:        old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0);
                    224: 
                    225:        myphar = (phar_archive_data *) pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
                    226:        myphar->is_persistent = PHAR_G(persist);
                    227:        /* estimate number of entries, can't be certain with tar files */
                    228:        zend_hash_init(&myphar->manifest, 2 + (totalsize >> 12),
                    229:                zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)myphar->is_persistent);
                    230:        zend_hash_init(&myphar->mounted_dirs, 5,
                    231:                zend_get_hash_value, NULL, (zend_bool)myphar->is_persistent);
                    232:        zend_hash_init(&myphar->virtual_dirs, 4 + (totalsize >> 11),
                    233:                zend_get_hash_value, NULL, (zend_bool)myphar->is_persistent);
                    234:        myphar->is_tar = 1;
                    235:        /* remember whether this entire phar was compressed with gz/bzip2 */
                    236:        myphar->flags = compression;
                    237: 
                    238:        entry.is_tar = 1;
                    239:        entry.is_crc_checked = 1;
                    240:        entry.phar = myphar;
                    241:        pos += sizeof(buf);
                    242: 
                    243:        do {
                    244:                phar_entry_info *newentry;
                    245: 
                    246:                pos = php_stream_tell(fp);
                    247:                hdr = (tar_header*) buf;
                    248:                sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
                    249:                if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) {
                    250:                        break;
                    251:                }
                    252:                memset(hdr->checksum, ' ', sizeof(hdr->checksum));
                    253:                sum2 = phar_tar_checksum(buf, old?sizeof(old_tar_header):sizeof(tar_header));
                    254: 
                    255:                size = entry.uncompressed_filesize = entry.compressed_filesize =
                    256:                        phar_tar_number(hdr->size, sizeof(hdr->size));
                    257: 
                    258:                if (((!old && hdr->prefix[0] == 0) || old) && strlen(hdr->name) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
                    259:                        off_t curloc;
                    260: 
                    261:                        if (size > 511) {
                    262:                                if (error) {
                    263:                                        spprintf(error, 4096, "phar error: tar-based phar \"%s\" has signature that is larger than 511 bytes, cannot process", fname);
                    264:                                }
                    265: bail:
                    266:                                php_stream_close(fp);
                    267:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    268:                                return FAILURE;
                    269:                        }
                    270:                        curloc = php_stream_tell(fp);
                    271:                        read = php_stream_read(fp, buf, size);
                    272:                        if (read != size) {
                    273:                                if (error) {
                    274:                                        spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be read", fname);
                    275:                                }
                    276:                                goto bail;
                    277:                        }
                    278: #ifdef WORDS_BIGENDIAN
                    279: # define PHAR_GET_32(buffer) \
                    280:        (((((unsigned char*)(buffer))[3]) << 24) \
                    281:                | ((((unsigned char*)(buffer))[2]) << 16) \
                    282:                | ((((unsigned char*)(buffer))[1]) <<  8) \
                    283:                | (((unsigned char*)(buffer))[0]))
                    284: #else
                    285: # define PHAR_GET_32(buffer) (php_uint32) *(buffer)
                    286: #endif
                    287:                        myphar->sig_flags = PHAR_GET_32(buf);
                    288:                        if (FAILURE == phar_verify_signature(fp, php_stream_tell(fp) - size - 512, myphar->sig_flags, buf + 8, size - 8, fname, &myphar->signature, &myphar->sig_len, error TSRMLS_CC)) {
                    289:                                if (error) {
                    290:                                        char *save = *error;
                    291:                                        spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be verified: %s", fname, save);
                    292:                                        efree(save);
                    293:                                }
                    294:                                goto bail;
                    295:                        }
                    296:                        php_stream_seek(fp, curloc + 512, SEEK_SET);
                    297:                        /* signature checked out, let's ensure this is the last file in the phar */
                    298:                        if (((hdr->typeflag == '\0') || (hdr->typeflag == TAR_FILE)) && size > 0) {
                    299:                                /* this is not good enough - seek succeeds even on truncated tars */
                    300:                                php_stream_seek(fp, 512, SEEK_CUR);
                    301:                                if ((uint)php_stream_tell(fp) > totalsize) {
                    302:                                        if (error) {
                    303:                                                spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    304:                                        }
                    305:                                        php_stream_close(fp);
                    306:                                        phar_destroy_phar_data(myphar TSRMLS_CC);
                    307:                                        return FAILURE;
                    308:                                }
                    309:                        }
                    310: 
                    311:                        read = php_stream_read(fp, buf, sizeof(buf));
                    312: 
                    313:                        if (read != sizeof(buf)) {
                    314:                                if (error) {
                    315:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    316:                                }
                    317:                                php_stream_close(fp);
                    318:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    319:                                return FAILURE;
                    320:                        }
                    321: 
                    322:                        hdr = (tar_header*) buf;
                    323:                        sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
                    324: 
                    325:                        if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) {
                    326:                                break;
                    327:                        }
                    328: 
                    329:                        if (error) {
                    330:                                spprintf(error, 4096, "phar error: \"%s\" has entries after signature, invalid phar", fname);
                    331:                        }
                    332: 
                    333:                        goto bail;
                    334:                }
                    335: 
                    336:                if (!last_was_longlink && hdr->typeflag == 'L') {
                    337:                        last_was_longlink = 1;
                    338:                        /* support the ././@LongLink system for storing long filenames */
                    339:                        entry.filename_len = entry.uncompressed_filesize;
                    340:                        entry.filename = pemalloc(entry.filename_len+1, myphar->is_persistent);
                    341: 
                    342:                        read = php_stream_read(fp, entry.filename, entry.filename_len);
                    343:                        if (read != entry.filename_len) {
                    344:                                efree(entry.filename);
                    345:                                if (error) {
                    346:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    347:                                }
                    348:                                php_stream_close(fp);
                    349:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    350:                                return FAILURE;
                    351:                        }
                    352:                        entry.filename[entry.filename_len] = '\0';
                    353: 
                    354:                        /* skip blank stuff */
                    355:                        size = ((size+511)&~511) - size;
                    356: 
                    357:                        /* this is not good enough - seek succeeds even on truncated tars */
                    358:                        php_stream_seek(fp, size, SEEK_CUR);
                    359:                        if ((uint)php_stream_tell(fp) > totalsize) {
                    360:                                efree(entry.filename);
                    361:                                if (error) {
                    362:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    363:                                }
                    364:                                php_stream_close(fp);
                    365:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    366:                                return FAILURE;
                    367:                        }
                    368: 
                    369:                        read = php_stream_read(fp, buf, sizeof(buf));
                    370:        
                    371:                        if (read != sizeof(buf)) {
                    372:                                efree(entry.filename);
                    373:                                if (error) {
                    374:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    375:                                }
                    376:                                php_stream_close(fp);
                    377:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    378:                                return FAILURE;
                    379:                        }
                    380:                        continue;
                    381:                } else if (!last_was_longlink && !old && hdr->prefix[0] != 0) {
                    382:                        char name[256];
                    383:                        int i, j;
                    384: 
                    385:                        for (i = 0; i < 155; i++) {
                    386:                                name[i] = hdr->prefix[i];
                    387:                                if (name[i] == '\0') {
                    388:                                        break;
                    389:                                }
                    390:                        }
                    391:                        name[i++] = '/';
                    392:                        for (j = 0; j < 100; j++) {
                    393:                                name[i+j] = hdr->name[j];
                    394:                                if (name[i+j] == '\0') {
                    395:                                        break;
                    396:                                }
                    397:                        }
                    398: 
                    399:                        entry.filename_len = i+j;
                    400: 
                    401:                        if (name[entry.filename_len - 1] == '/') {
                    402:                                /* some tar programs store directories with trailing slash */
                    403:                                entry.filename_len--;
                    404:                        }
                    405:                        entry.filename = pestrndup(name, entry.filename_len, myphar->is_persistent);
                    406:                } else if (!last_was_longlink) {
                    407:                        int i;
                    408: 
                    409:                        /* calculate strlen, which can be no longer than 100 */
                    410:                        for (i = 0; i < 100; i++) {
                    411:                                if (hdr->name[i] == '\0') {
                    412:                                        break;
                    413:                                }
                    414:                        }
                    415:                        entry.filename_len = i;
                    416:                        entry.filename = pestrndup(hdr->name, i, myphar->is_persistent);
                    417: 
                    418:                        if (entry.filename[entry.filename_len - 1] == '/') {
                    419:                                /* some tar programs store directories with trailing slash */
                    420:                                entry.filename[entry.filename_len - 1] = '\0';
                    421:                                entry.filename_len--;
                    422:                        }
                    423:                }
                    424:                last_was_longlink = 0;
                    425: 
                    426:                phar_add_virtual_dirs(myphar, entry.filename, entry.filename_len TSRMLS_CC);
                    427: 
                    428:                if (sum1 != sum2) {
                    429:                        if (error) {
                    430:                                spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename);
                    431:                        }
                    432:                        pefree(entry.filename, myphar->is_persistent);
                    433:                        php_stream_close(fp);
                    434:                        phar_destroy_phar_data(myphar TSRMLS_CC);
                    435:                        return FAILURE;
                    436:                }
                    437: 
                    438:                entry.tar_type = ((old & (hdr->typeflag == '\0')) ? TAR_FILE : hdr->typeflag);
                    439:                entry.offset = entry.offset_abs = pos; /* header_offset unused in tar */
                    440:                entry.fp_type = PHAR_FP;
                    441:                entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK;
                    442:                entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime));
                    443:                entry.is_persistent = myphar->is_persistent;
                    444: #ifndef S_ISDIR
                    445: #define S_ISDIR(mode)  (((mode)&S_IFMT) == S_IFDIR)
                    446: #endif
                    447:                if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) {
                    448:                        entry.tar_type = TAR_DIR;
                    449:                }
                    450: 
                    451:                if (entry.tar_type == TAR_DIR) {
                    452:                        entry.is_dir = 1;
                    453:                } else {
                    454:                        entry.is_dir = 0;
                    455:                }
                    456: 
                    457:                entry.link = NULL;
                    458: 
                    459:                if (entry.tar_type == TAR_LINK) {
                    460:                        if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
                    461:                                if (error) {
                    462:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
                    463:                                }
                    464:                                pefree(entry.filename, entry.is_persistent);
                    465:                                php_stream_close(fp);
                    466:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    467:                                return FAILURE;
                    468:                        }
                    469:                        entry.link = estrdup(hdr->linkname);
                    470:                } else if (entry.tar_type == TAR_SYMLINK) {
                    471:                        entry.link = estrdup(hdr->linkname);
                    472:                }
                    473:                phar_set_inode(&entry TSRMLS_CC);
                    474:                zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);
                    475: 
                    476:                if (entry.is_persistent) {
                    477:                        ++entry.manifest_pos;
                    478:                }
                    479: 
                    480:                if (entry.filename_len >= sizeof(".phar/.metadata")-1 && !memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
                    481:                        if (FAILURE == phar_tar_process_metadata(newentry, fp TSRMLS_CC)) {
                    482:                                if (error) {
                    483:                                        spprintf(error, 4096, "phar error: tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname, entry.filename);
                    484:                                }
                    485:                                php_stream_close(fp);
                    486:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    487:                                return FAILURE;
                    488:                        }
                    489:                }
                    490: 
                    491:                if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
                    492:                        /* found explicit alias */
                    493:                        if (size > 511) {
                    494:                                if (error) {
                    495:                                        spprintf(error, 4096, "phar error: tar-based phar \"%s\" has alias that is larger than 511 bytes, cannot process", fname);
                    496:                                }
                    497:                                php_stream_close(fp);
                    498:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    499:                                return FAILURE;
                    500:                        }
                    501: 
                    502:                        read = php_stream_read(fp, buf, size);
                    503: 
                    504:                        if (read == size) {
                    505:                                buf[size] = '\0';
                    506:                                if (!phar_validate_alias(buf, size)) {
                    507:                                        if (size > 50) {
                    508:                                                buf[50] = '.';
                    509:                                                buf[51] = '.';
                    510:                                                buf[52] = '.';
                    511:                                                buf[53] = '\0';
                    512:                                        }
                    513: 
                    514:                                        if (error) {
                    515:                                                spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname);
                    516:                                        }
                    517: 
                    518:                                        php_stream_close(fp);
                    519:                                        phar_destroy_phar_data(myphar TSRMLS_CC);
                    520:                                        return FAILURE;
                    521:                                }
                    522: 
                    523:                                actual_alias = pestrndup(buf, size, myphar->is_persistent);
                    524:                                myphar->alias = actual_alias;
                    525:                                myphar->alias_len = size;
                    526:                                php_stream_seek(fp, pos, SEEK_SET);
                    527:                        } else {
                    528:                                if (error) {
                    529:                                        spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname);
                    530:                                }
                    531: 
                    532:                                php_stream_close(fp);
                    533:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    534:                                return FAILURE;
                    535:                        }
                    536:                }
                    537: 
                    538:                size = (size+511)&~511;
                    539: 
                    540:                if (((hdr->typeflag == '\0') || (hdr->typeflag == TAR_FILE)) && size > 0) {
                    541:                        /* this is not good enough - seek succeeds even on truncated tars */
                    542:                        php_stream_seek(fp, size, SEEK_CUR);
                    543:                        if ((uint)php_stream_tell(fp) > totalsize) {
                    544:                                if (error) {
                    545:                                        spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    546:                                }
                    547:                                php_stream_close(fp);
                    548:                                phar_destroy_phar_data(myphar TSRMLS_CC);
                    549:                                return FAILURE;
                    550:                        }
                    551:                }
                    552: 
                    553:                read = php_stream_read(fp, buf, sizeof(buf));
                    554: 
                    555:                if (read != sizeof(buf)) {
                    556:                        if (error) {
                    557:                                spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
                    558:                        }
                    559:                        php_stream_close(fp);
                    560:                        phar_destroy_phar_data(myphar TSRMLS_CC);
                    561:                        return FAILURE;
                    562:                }
                    563:        } while (read != 0);
                    564: 
                    565:        if (zend_hash_exists(&(myphar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
                    566:                myphar->is_data = 0;
                    567:        } else {
                    568:                myphar->is_data = 1;
                    569:        }
                    570: 
                    571:        /* ensure signature set */
                    572:        if (!myphar->is_data && PHAR_G(require_hash) && !myphar->signature) {
                    573:                php_stream_close(fp);
                    574:                phar_destroy_phar_data(myphar TSRMLS_CC);
                    575:                if (error) {
                    576:                        spprintf(error, 0, "tar-based phar \"%s\" does not have a signature", fname);
                    577:                }
                    578:                return FAILURE;
                    579:        }
                    580: 
                    581:        myphar->fname = pestrndup(fname, fname_len, myphar->is_persistent);
                    582: #ifdef PHP_WIN32
                    583:        phar_unixify_path_separators(myphar->fname, fname_len);
                    584: #endif
                    585:        myphar->fname_len = fname_len;
                    586:        myphar->fp = fp;
                    587:        p = strrchr(myphar->fname, '/');
                    588: 
                    589:        if (p) {
                    590:                myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p);
                    591:                if (myphar->ext == p) {
                    592:                        myphar->ext = memchr(p + 1, '.', (myphar->fname + fname_len) - p - 1);
                    593:                }
                    594:                if (myphar->ext) {
                    595:                        myphar->ext_len = (myphar->fname + fname_len) - myphar->ext;
                    596:                }
                    597:        }
                    598: 
                    599:        phar_request_initialize(TSRMLS_C);
                    600: 
                    601:        if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) {
                    602:                if (error) {
                    603:                        spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname);
                    604:                }
                    605:                php_stream_close(fp);
                    606:                phar_destroy_phar_data(myphar TSRMLS_CC);
                    607:                return FAILURE;
                    608:        }
                    609: 
                    610:        myphar = *actual;
                    611: 
                    612:        if (actual_alias) {
                    613:                phar_archive_data **fd_ptr;
                    614: 
                    615:                myphar->is_temporary_alias = 0;
                    616: 
                    617:                if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void **)&fd_ptr)) {
                    618:                        if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) {
                    619:                                if (error) {
                    620:                                        spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
                    621:                                }
                    622:                                zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len);
                    623:                                return FAILURE;
                    624:                        }
                    625:                }
                    626: 
                    627:                zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
                    628:        } else {
                    629:                phar_archive_data **fd_ptr;
                    630: 
                    631:                if (alias_len) {
                    632:                        if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
                    633:                                if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
                    634:                                        if (error) {
                    635:                                                spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
                    636:                                        }
                    637:                                        zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len);
                    638:                                        return FAILURE;
                    639:                                }
                    640:                        }
                    641:                        zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
                    642:                        myphar->alias = pestrndup(alias, alias_len, myphar->is_persistent);
                    643:                        myphar->alias_len = alias_len;
                    644:                } else {
                    645:                        myphar->alias = pestrndup(myphar->fname, fname_len, myphar->is_persistent);
                    646:                        myphar->alias_len = fname_len;
                    647:                }
                    648: 
                    649:                myphar->is_temporary_alias = 1;
                    650:        }
                    651: 
                    652:        if (pphar) {
                    653:                *pphar = myphar;
                    654:        }
                    655: 
                    656:        return SUCCESS;
                    657: }
                    658: /* }}} */
                    659: 
                    660: struct _phar_pass_tar_info {
                    661:        php_stream *old;
                    662:        php_stream *new;
                    663:        int free_fp;
                    664:        int free_ufp;
                    665:        char **error;
                    666: };
                    667: 
                    668: static int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
                    669: {
                    670:        tar_header header;
                    671:        size_t pos;
                    672:        phar_entry_info *entry = (phar_entry_info *) pDest;
                    673:        struct _phar_pass_tar_info *fp = (struct _phar_pass_tar_info *)argument;
                    674:        char padding[512];
                    675: 
                    676:        if (entry->is_mounted) {
                    677:                return ZEND_HASH_APPLY_KEEP;
                    678:        }
                    679: 
                    680:        if (entry->is_deleted) {
                    681:                if (entry->fp_refcount <= 0) {
                    682:                        return ZEND_HASH_APPLY_REMOVE;
                    683:                } else {
                    684:                        /* we can't delete this in-memory until it is closed */
                    685:                        return ZEND_HASH_APPLY_KEEP;
                    686:                }
                    687:        }
                    688: 
                    689:        phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len TSRMLS_CC);
                    690:        memset((char *) &header, 0, sizeof(header));
                    691: 
                    692:        if (entry->filename_len > 100) {
                    693:                char *boundary;
                    694:                if (entry->filename_len > 256) {
                    695:                        if (fp->error) {
                    696:                                spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too long for tar file format", entry->phar->fname, entry->filename);
                    697:                        }
                    698:                        return ZEND_HASH_APPLY_STOP;
                    699:                }
                    700:                boundary = entry->filename + entry->filename_len - 101;
                    701:                while (*boundary && *boundary != '/') {
                    702:                        ++boundary;
                    703:                }
                    704:                if (!*boundary || ((boundary - entry->filename) > 155)) {
                    705:                        if (fp->error) {
                    706:                                spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too long for tar file format", entry->phar->fname, entry->filename);
                    707:                        }
                    708:                        return ZEND_HASH_APPLY_STOP;
                    709:                }
                    710:                memcpy(header.prefix, entry->filename, boundary - entry->filename);
                    711:                memcpy(header.name, boundary + 1, entry->filename_len - (boundary + 1 - entry->filename));
                    712:        } else {
                    713:                memcpy(header.name, entry->filename, entry->filename_len);
                    714:        }
                    715: 
                    716:        phar_tar_octal(header.mode, entry->flags & PHAR_ENT_PERM_MASK, sizeof(header.mode)-1);
                    717: 
                    718:        if (FAILURE == phar_tar_octal(header.size, entry->uncompressed_filesize, sizeof(header.size)-1)) {
                    719:                if (fp->error) {
                    720:                        spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
                    721:                }
                    722:                return ZEND_HASH_APPLY_STOP;
                    723:        }
                    724: 
                    725:        if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) {
                    726:                if (fp->error) {
                    727:                        spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, file modification time of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
                    728:                }
                    729:                return ZEND_HASH_APPLY_STOP;
                    730:        }
                    731: 
                    732:        /* calc checksum */
                    733:        header.typeflag = entry->tar_type;
                    734: 
                    735:        if (entry->link) {
                    736:                strncpy(header.linkname, entry->link, strlen(entry->link));
                    737:        }
                    738: 
                    739:        strncpy(header.magic, "ustar", sizeof("ustar")-1);
                    740:        strncpy(header.version, "00", sizeof("00")-1);
                    741:        strncpy(header.checksum, "        ", sizeof("        ")-1);
                    742:        entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header));
                    743: 
                    744:        if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) {
                    745:                if (fp->error) {
                    746:                        spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, checksum of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
                    747:                }
                    748:                return ZEND_HASH_APPLY_STOP;
                    749:        }
                    750: 
                    751:        /* write header */
                    752:        entry->header_offset = php_stream_tell(fp->new);
                    753: 
                    754:        if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) {
                    755:                if (fp->error) {
                    756:                        spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for  file \"%s\" could not be written", entry->phar->fname, entry->filename);
                    757:                }
                    758:                return ZEND_HASH_APPLY_STOP;
                    759:        }
                    760: 
                    761:        pos = php_stream_tell(fp->new); /* save start of file within tar */
                    762: 
                    763:        /* write contents */
                    764:        if (entry->uncompressed_filesize) {
                    765:                if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) {
                    766:                        return ZEND_HASH_APPLY_STOP;
                    767:                }
                    768: 
                    769:                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
                    770:                        if (fp->error) {
                    771:                                spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written, seek failed", entry->phar->fname, entry->filename);
                    772:                        }
                    773:                        return ZEND_HASH_APPLY_STOP;
                    774:                }
                    775: 
                    776:                if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize, NULL)) {
                    777:                        if (fp->error) {
                    778:                                spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename);
                    779:                        }
                    780:                        return ZEND_HASH_APPLY_STOP;
                    781:                }
                    782: 
                    783:                memset(padding, 0, 512);
                    784:                php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
                    785:        }
                    786: 
                    787:        if (!entry->is_modified && entry->fp_refcount) {
                    788:                /* open file pointers refer to this fp, do not free the stream */
                    789:                switch (entry->fp_type) {
                    790:                        case PHAR_FP:
                    791:                                fp->free_fp = 0;
                    792:                                break;
                    793:                        case PHAR_UFP:
                    794:                                fp->free_ufp = 0;
                    795:                        default:
                    796:                                break;
                    797:                }
                    798:        }
                    799: 
                    800:        entry->is_modified = 0;
                    801: 
                    802:        if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
                    803:                if (!entry->fp_refcount) {
                    804:                        php_stream_close(entry->fp);
                    805:                }
                    806:                entry->fp = NULL;
                    807:        }
                    808: 
                    809:        entry->fp_type = PHAR_FP;
                    810: 
                    811:        /* note new location within tar */
                    812:        entry->offset = entry->offset_abs = pos;
                    813:        return ZEND_HASH_APPLY_KEEP;
                    814: }
                    815: /* }}} */
                    816: 
                    817: int phar_tar_setmetadata(zval *metadata, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
                    818: {
                    819:        php_serialize_data_t metadata_hash;
                    820: 
                    821:        if (entry->metadata_str.c) {
                    822:                smart_str_free(&entry->metadata_str);
                    823:        }
                    824: 
                    825:        entry->metadata_str.c = 0;
                    826:        entry->metadata_str.len = 0;
                    827:        PHP_VAR_SERIALIZE_INIT(metadata_hash);
                    828:        php_var_serialize(&entry->metadata_str, &metadata, &metadata_hash TSRMLS_CC);
                    829:        PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
                    830:        entry->uncompressed_filesize = entry->compressed_filesize = entry->metadata_str.len;
                    831: 
                    832:        if (entry->fp && entry->fp_type == PHAR_MOD) {
                    833:                php_stream_close(entry->fp);
                    834:        }
                    835: 
                    836:        entry->fp_type = PHAR_MOD;
                    837:        entry->is_modified = 1;
                    838:        entry->fp = php_stream_fopen_tmpfile();
                    839:        entry->offset = entry->offset_abs = 0;
                    840: 
                    841:        if (entry->metadata_str.len != php_stream_write(entry->fp, entry->metadata_str.c, entry->metadata_str.len)) {
                    842:                spprintf(error, 0, "phar tar error: unable to write metadata to magic metadata file \"%s\"", entry->filename);
                    843:                zend_hash_del(&(entry->phar->manifest), entry->filename, entry->filename_len);
                    844:                return ZEND_HASH_APPLY_STOP;
                    845:        }
                    846: 
                    847:        return ZEND_HASH_APPLY_KEEP;
                    848: }
                    849: /* }}} */
                    850: 
                    851: static int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC) /* {{{ */
                    852: {
                    853:        int lookfor_len;
                    854:        struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument;
                    855:        char *lookfor, **error = i->error;
                    856:        phar_entry_info *entry = (phar_entry_info *)pDest, *metadata, newentry = {0};
                    857: 
                    858:        if (entry->filename_len >= sizeof(".phar/.metadata") && !memcmp(entry->filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
                    859:                if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 && !memcmp(entry->filename, ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1)) {
                    860:                        return phar_tar_setmetadata(entry->phar->metadata, entry, error TSRMLS_CC);
                    861:                }
                    862:                /* search for the file this metadata entry references */
                    863:                if (entry->filename_len >= sizeof(".phar/.metadata/") + sizeof("/.metadata.bin") - 1 && !zend_hash_exists(&(entry->phar->manifest), entry->filename + sizeof(".phar/.metadata/") - 1, entry->filename_len - (sizeof("/.metadata.bin") - 1 + sizeof(".phar/.metadata/") - 1))) {
                    864:                        /* this is orphaned metadata, erase it */
                    865:                        return ZEND_HASH_APPLY_REMOVE;
                    866:                }
                    867:                /* we can keep this entry, the file that refers to it exists */
                    868:                return ZEND_HASH_APPLY_KEEP;
                    869:        }
                    870: 
                    871:        if (!entry->is_modified) {
                    872:                return ZEND_HASH_APPLY_KEEP;
                    873:        }
                    874: 
                    875:        /* now we are dealing with regular files, so look for metadata */
                    876:        lookfor_len = spprintf(&lookfor, 0, ".phar/.metadata/%s/.metadata.bin", entry->filename);
                    877: 
                    878:        if (!entry->metadata) {
                    879:                zend_hash_del(&(entry->phar->manifest), lookfor, lookfor_len);
                    880:                efree(lookfor);
                    881:                return ZEND_HASH_APPLY_KEEP;
                    882:        }
                    883: 
                    884:        if (SUCCESS == zend_hash_find(&(entry->phar->manifest), lookfor, lookfor_len, (void **)&metadata)) {
                    885:                int ret;
                    886:                ret = phar_tar_setmetadata(entry->metadata, metadata, error TSRMLS_CC);
                    887:                efree(lookfor);
                    888:                return ret;
                    889:        }
                    890: 
                    891:        newentry.filename = lookfor;
                    892:        newentry.filename_len = lookfor_len;
                    893:        newentry.phar = entry->phar;
                    894:        newentry.tar_type = TAR_FILE;
                    895:        newentry.is_tar = 1;
                    896: 
                    897:        if (SUCCESS != zend_hash_add(&(entry->phar->manifest), lookfor, lookfor_len, (void *)&newentry, sizeof(phar_entry_info), (void **)&metadata)) {
                    898:                efree(lookfor);
                    899:                spprintf(error, 0, "phar tar error: unable to add magic metadata file to manifest for file \"%s\"", entry->filename);
                    900:                return ZEND_HASH_APPLY_STOP;
                    901:        }
                    902: 
                    903:        return phar_tar_setmetadata(entry->metadata, metadata, error TSRMLS_CC);
                    904: }
                    905: /* }}} */
                    906: 
                    907: int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
                    908: {
                    909:        phar_entry_info entry = {0};
                    910:        static const char newstub[] = "<?php // tar-based phar archive stub file\n__HALT_COMPILER();";
                    911:        php_stream *oldfile, *newfile, *stubfile;
                    912:        int closeoldfile, free_user_stub, signature_length;
                    913:        struct _phar_pass_tar_info pass;
                    914:        char *buf, *signature, *tmp, sigbuf[8];
                    915:        char halt_stub[] = "__HALT_COMPILER();";
                    916: 
                    917:        entry.flags = PHAR_ENT_PERM_DEF_FILE;
                    918:        entry.timestamp = time(NULL);
                    919:        entry.is_modified = 1;
                    920:        entry.is_crc_checked = 1;
                    921:        entry.is_tar = 1;
                    922:        entry.tar_type = '0';
                    923:        entry.phar = phar;
                    924:        entry.fp_type = PHAR_MOD;
                    925: 
                    926:        if (phar->is_persistent) {
                    927:                if (error) {
                    928:                        spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname);
                    929:                }
                    930:                return EOF;
                    931:        }
                    932: 
                    933:        if (phar->is_data) {
                    934:                goto nostub;
                    935:        }
                    936: 
                    937:        /* set alias */
                    938:        if (!phar->is_temporary_alias && phar->alias_len) {
                    939:                entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
                    940:                entry.filename_len = sizeof(".phar/alias.txt")-1;
                    941:                entry.fp = php_stream_fopen_tmpfile();
                    942: 
                    943:                if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
                    944:                        if (error) {
                    945:                                spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
                    946:                        }
                    947:                        return EOF;
                    948:                }
                    949: 
                    950:                entry.uncompressed_filesize = phar->alias_len;
                    951: 
                    952:                if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
                    953:                        if (error) {
                    954:                                spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
                    955:                        }
                    956:                        return EOF;
                    957:                }
                    958:        } else {
                    959:                zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
                    960:        }
                    961: 
                    962:        /* set stub */
                    963:        if (user_stub && !defaultstub) {
                    964:                char *pos;
                    965:                if (len < 0) {
                    966:                        /* resource passed in */
                    967:                        if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
                    968:                                if (error) {
                    969:                                        spprintf(error, 0, "unable to access resource to copy stub to new tar-based phar \"%s\"", phar->fname);
                    970:                                }
                    971:                                return EOF;
                    972:                        }
                    973:                        if (len == -1) {
                    974:                                len = PHP_STREAM_COPY_ALL;
                    975:                        } else {
                    976:                                len = -len;
                    977:                        }
                    978:                        user_stub = 0;
                    979: #if PHP_MAJOR_VERSION >= 6
                    980:                        if (!(len = php_stream_copy_to_mem(stubfile, (void **) &user_stub, len, 0)) || !user_stub) {
                    981: #else
                    982:                        if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
                    983: #endif
                    984:                                if (error) {
                    985:                                        spprintf(error, 0, "unable to read resource to copy stub to new tar-based phar \"%s\"", phar->fname);
                    986:                                }
                    987:                                return EOF;
                    988:                        }
                    989:                        free_user_stub = 1;
                    990:                } else {
                    991:                        free_user_stub = 0;
                    992:                }
                    993: 
                    994:                tmp = estrndup(user_stub, len);
                    995:                if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
                    996:                        efree(tmp);
                    997:                        if (error) {
                    998:                                spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname);
                    999:                        }
                   1000:                        if (free_user_stub) {
                   1001:                                efree(user_stub);
                   1002:                        }
                   1003:                        return EOF;
                   1004:                }
                   1005:                pos = user_stub + (pos - tmp);
                   1006:                efree(tmp);
                   1007: 
                   1008:                len = pos - user_stub + 18;
                   1009:                entry.fp = php_stream_fopen_tmpfile();
                   1010:                entry.uncompressed_filesize = len + 5;
                   1011: 
                   1012:                if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
                   1013:                ||            5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
                   1014:                        if (error) {
                   1015:                                spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname);
                   1016:                        }
                   1017:                        if (free_user_stub) {
                   1018:                                efree(user_stub);
                   1019:                        }
                   1020:                        php_stream_close(entry.fp);
                   1021:                        return EOF;
                   1022:                }
                   1023: 
                   1024:                entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
                   1025:                entry.filename_len = sizeof(".phar/stub.php")-1;
                   1026:                zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
                   1027: 
                   1028:                if (free_user_stub) {
                   1029:                        efree(user_stub);
                   1030:                }
                   1031:        } else {
                   1032:                /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
                   1033:                entry.fp = php_stream_fopen_tmpfile();
                   1034: 
                   1035:                if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
                   1036:                        php_stream_close(entry.fp);
                   1037:                        if (error) {
                   1038:                                spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
                   1039:                        }
                   1040:                        return EOF;
                   1041:                }
                   1042: 
                   1043:                entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
                   1044:                entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
                   1045:                entry.filename_len = sizeof(".phar/stub.php")-1;
                   1046: 
                   1047:                if (!defaultstub) {
                   1048:                        if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
                   1049:                                if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
                   1050:                                        php_stream_close(entry.fp);
                   1051:                                        efree(entry.filename);
                   1052:                                        if (error) {
                   1053:                                                spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname);
                   1054:                                        }
                   1055:                                        return EOF;
                   1056:                                }
                   1057:                        } else {
                   1058:                                php_stream_close(entry.fp);
                   1059:                                efree(entry.filename);
                   1060:                        }
                   1061:                } else {
                   1062:                        if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
                   1063:                                php_stream_close(entry.fp);
                   1064:                                efree(entry.filename);
                   1065:                                if (error) {
                   1066:                                        spprintf(error, 0, "unable to overwrite stub in tar-based phar \"%s\"", phar->fname);
                   1067:                                }
                   1068:                                return EOF;
                   1069:                        }
                   1070:                }
                   1071:        }
                   1072: nostub:
                   1073:        if (phar->fp && !phar->is_brandnew) {
                   1074:                oldfile = phar->fp;
                   1075:                closeoldfile = 0;
                   1076:                php_stream_rewind(oldfile);
                   1077:        } else {
                   1078:                oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
                   1079:                closeoldfile = oldfile != NULL;
                   1080:        }
                   1081: 
                   1082:        newfile = php_stream_fopen_tmpfile();
                   1083: 
                   1084:        if (!newfile) {
                   1085:                if (error) {
                   1086:                        spprintf(error, 0, "unable to create temporary file");
                   1087:                }
                   1088:                if (closeoldfile) {
                   1089:                        php_stream_close(oldfile);
                   1090:                }
                   1091:                return EOF;
                   1092:        }
                   1093: 
                   1094:        pass.old = oldfile;
                   1095:        pass.new = newfile;
                   1096:        pass.error = error;
                   1097:        pass.free_fp = 1;
                   1098:        pass.free_ufp = 1;
                   1099: 
                   1100:        if (phar->metadata) {
                   1101:                phar_entry_info *mentry;
                   1102:                if (SUCCESS == zend_hash_find(&(phar->manifest), ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1, (void **)&mentry)) {
                   1103:                        if (ZEND_HASH_APPLY_KEEP != phar_tar_setmetadata(phar->metadata, mentry, error TSRMLS_CC)) {
                   1104:                                if (closeoldfile) {
                   1105:                                        php_stream_close(oldfile);
                   1106:                                }
                   1107:                                return EOF;
                   1108:                        }
                   1109:                } else {
                   1110:                        phar_entry_info newentry = {0};
                   1111: 
                   1112:                        newentry.filename = estrndup(".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1);
                   1113:                        newentry.filename_len = sizeof(".phar/.metadata.bin")-1;
                   1114:                        newentry.phar = phar;
                   1115:                        newentry.tar_type = TAR_FILE;
                   1116:                        newentry.is_tar = 1;
                   1117: 
                   1118:                        if (SUCCESS != zend_hash_add(&(phar->manifest), ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1, (void *)&newentry, sizeof(phar_entry_info), (void **)&mentry)) {
                   1119:                                spprintf(error, 0, "phar tar error: unable to add magic metadata file to manifest for phar archive \"%s\"", phar->fname);
                   1120:                                if (closeoldfile) {
                   1121:                                        php_stream_close(oldfile);
                   1122:                                }
                   1123:                                return EOF;
                   1124:                        }
                   1125: 
                   1126:                        if (ZEND_HASH_APPLY_KEEP != phar_tar_setmetadata(phar->metadata, mentry, error TSRMLS_CC)) {
                   1127:                                zend_hash_del(&(phar->manifest), ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1);
                   1128:                                if (closeoldfile) {
                   1129:                                        php_stream_close(oldfile);
                   1130:                                }
                   1131:                                return EOF;
                   1132:                        }
                   1133:                }
                   1134:        }
                   1135: 
                   1136:        zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_setupmetadata, (void *) &pass TSRMLS_CC);
                   1137: 
                   1138:        if (error && *error) {
                   1139:                if (closeoldfile) {
                   1140:                        php_stream_close(oldfile);
                   1141:                }
                   1142: 
                   1143:                /* on error in the hash iterator above, error is set */
                   1144:                php_stream_close(newfile);
                   1145:                return EOF;
                   1146:        }
                   1147: 
                   1148:        zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
                   1149: 
                   1150:        /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
                   1151:        if (!phar->is_data || phar->sig_flags) {
                   1152:                if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, error TSRMLS_CC)) {
                   1153:                        if (error) {
                   1154:                                char *save = *error;
                   1155:                                spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", save);
                   1156:                                efree(save);
                   1157:                        }
                   1158: 
                   1159:                        if (closeoldfile) {
                   1160:                                php_stream_close(oldfile);
                   1161:                        }
                   1162: 
                   1163:                        php_stream_close(newfile);
                   1164:                        return EOF;
                   1165:                }
                   1166: 
                   1167:                entry.filename = ".phar/signature.bin";
                   1168:                entry.filename_len = sizeof(".phar/signature.bin")-1;
                   1169:                entry.fp = php_stream_fopen_tmpfile();
                   1170: 
                   1171: #ifdef WORDS_BIGENDIAN
                   1172: # define PHAR_SET_32(var, buffer) \
                   1173:        *(php_uint32 *)(var) = (((((unsigned char*)&(buffer))[3]) << 24) \
                   1174:                | ((((unsigned char*)&(buffer))[2]) << 16) \
                   1175:                | ((((unsigned char*)&(buffer))[1]) << 8) \
                   1176:                | (((unsigned char*)&(buffer))[0]))
                   1177: #else
                   1178: # define PHAR_SET_32(var, buffer) *(php_uint32 *)(var) = (php_uint32) (buffer)
                   1179: #endif
                   1180:                PHAR_SET_32(sigbuf, phar->sig_flags);
                   1181:                PHAR_SET_32(sigbuf + 4, signature_length);
                   1182: 
                   1183:                if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) {
                   1184:                        efree(signature);
                   1185:                        if (error) {
                   1186:                                spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname);
                   1187:                        }
                   1188: 
                   1189:                        if (closeoldfile) {
                   1190:                                php_stream_close(oldfile);
                   1191:                        }
                   1192:                        php_stream_close(newfile);
                   1193:                        return EOF;
                   1194:                }
                   1195: 
                   1196:                efree(signature);
                   1197:                entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
                   1198:                /* throw out return value and write the signature */
                   1199:                entry.filename_len = phar_tar_writeheaders((void *)&entry, (void *)&pass TSRMLS_CC);
                   1200: 
                   1201:                if (error && *error) {
                   1202:                        if (closeoldfile) {
                   1203:                                php_stream_close(oldfile);
                   1204:                        }
                   1205:                        /* error is set by writeheaders */
                   1206:                        php_stream_close(newfile);
                   1207:                        return EOF;
                   1208:                }
                   1209:        } /* signature */
                   1210: 
                   1211:        /* add final zero blocks */
                   1212:        buf = (char *) ecalloc(1024, 1);
                   1213:        php_stream_write(newfile, buf, 1024);
                   1214:        efree(buf);
                   1215: 
                   1216:        if (closeoldfile) {
                   1217:                php_stream_close(oldfile);
                   1218:        }
                   1219: 
                   1220:        /* on error in the hash iterator above, error is set */
                   1221:        if (error && *error) {
                   1222:                php_stream_close(newfile);
                   1223:                return EOF;
                   1224:        }
                   1225: 
                   1226:        if (phar->fp && pass.free_fp) {
                   1227:                php_stream_close(phar->fp);
                   1228:        }
                   1229: 
                   1230:        if (phar->ufp) {
                   1231:                if (pass.free_ufp) {
                   1232:                        php_stream_close(phar->ufp);
                   1233:                }
                   1234:                phar->ufp = NULL;
                   1235:        }
                   1236: 
                   1237:        phar->is_brandnew = 0;
                   1238:        php_stream_rewind(newfile);
                   1239: 
                   1240:        if (phar->donotflush) {
                   1241:                /* deferred flush */
                   1242:                phar->fp = newfile;
                   1243:        } else {
                   1244:                phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
                   1245:                if (!phar->fp) {
                   1246:                        phar->fp = newfile;
                   1247:                        if (error) {
                   1248:                                spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname);
                   1249:                        }
                   1250:                        return EOF;
                   1251:                }
                   1252: 
                   1253:                if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
                   1254:                        php_stream_filter *filter;
                   1255:                        /* to properly compress, we have to tell zlib to add a zlib header */
                   1256:                        zval filterparams;
                   1257: 
                   1258:                        array_init(&filterparams);
                   1259: /* this is defined in zlib's zconf.h */
                   1260: #ifndef MAX_WBITS
                   1261: #define MAX_WBITS 15
                   1262: #endif
                   1263:                        add_assoc_long(&filterparams, "window", MAX_WBITS + 16);
                   1264:                        filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
                   1265:                        zval_dtor(&filterparams);
                   1266: 
                   1267:                        if (!filter) {
                   1268:                                /* copy contents uncompressed rather than lose them */
                   1269:                                phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   1270:                                php_stream_close(newfile);
                   1271:                                if (error) {
                   1272:                                        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);
                   1273:                                }
                   1274:                                return EOF;
                   1275:                        }
                   1276: 
                   1277:                        php_stream_filter_append(&phar->fp->writefilters, filter);
                   1278:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   1279:                        php_stream_filter_flush(filter, 1);
                   1280:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
                   1281:                        php_stream_close(phar->fp);
                   1282:                        /* use the temp stream as our base */
                   1283:                        phar->fp = newfile;
                   1284:                } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
                   1285:                        php_stream_filter *filter;
                   1286: 
                   1287:                        filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
                   1288:                        php_stream_filter_append(&phar->fp->writefilters, filter);
                   1289:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   1290:                        php_stream_filter_flush(filter, 1);
                   1291:                        php_stream_filter_remove(filter, 1 TSRMLS_CC);
                   1292:                        php_stream_close(phar->fp);
                   1293:                        /* use the temp stream as our base */
                   1294:                        phar->fp = newfile;
                   1295:                } else {
                   1296:                        phar_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
                   1297:                        /* we could also reopen the file in "rb" mode but there is no need for that */
                   1298:                        php_stream_close(newfile);
                   1299:                }
                   1300:        }
                   1301:        return EOF;
                   1302: }
                   1303: /* }}} */
                   1304: 
                   1305: /*
                   1306:  * Local variables:
                   1307:  * tab-width: 4
                   1308:  * c-basic-offset: 4
                   1309:  * End:
                   1310:  * vim600: noet sw=4 ts=4 fdm=marker
                   1311:  * vim<600: noet sw=4 ts=4
                   1312:  */

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