* This is used by phar_open_filename to process the manifest, but can be called
* directly.
*/
-int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+int phar_open_file(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) /* {{{ */
{
char b32[4], *buffer, *endbuffer, *savebuf;
phar_archive_data *mydata = NULL;
PHAR_GET_32(buffer, manifest_flags);
- manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
+ manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
+
+ manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
+ /* remember whether this entire phar was compressed with gz/bzip2 */
+ manifest_flags |= compression;
/* The lowest nibble contains the phar wide flags. The compression flags can */
/* be ignored on reading because it is being generated anyways. */
{
const char token[] = "__HALT_COMPILER();";
const char zip_magic[] = "PK\x03\x04";
+ const char gz_magic[] = "\x1f\x8b\x08";
+ const char bz_magic[] = "BZh";
char *pos, buffer[1024 + sizeof(token)], test = '\0';
const long readsize = sizeof(buffer) - sizeof(token);
const long tokenlen = sizeof(token) - 1;
long halt_offset;
size_t got;
-
- /* Maybe it's better to compile the file instead of just searching, */
- /* but we only want the offset. So we want a .re scanner to find it. */
+ php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
if (error) {
*error = NULL;
buffer[sizeof(buffer)-1] = '\0';
memset(buffer, 32, sizeof(token));
halt_offset = 0;
+
+ /* Maybe it's better to compile the file instead of just searching, */
+ /* but we only want the offset. So we want a .re scanner to find it. */
while(!php_stream_eof(fp)) {
if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
if (!test) {
test = '\1';
pos = buffer+tokenlen;
+ if (!memcmp(pos, gz_magic, 3)) {
+ char err = 0;
+ php_stream_filter *filter;
+ php_stream *temp;
+ /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
+ zval filterparams;
+
+ array_init(&filterparams);
+ add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
+ /* entire file is gzip-compressed, uncompress to temporary file */
+ if (!(temp = php_stream_fopen_tmpfile())) {
+ MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
+ }
+ php_stream_rewind(fp);
+ filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
+ if (!filter) {
+ err = 1;
+ add_assoc_long(&filterparams, "window", MAX_WBITS);
+ filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
+ }
+ zval_dtor(&filterparams);
+ php_stream_filter_append(&temp->writefilters, filter);
+ if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
+ if (err) {
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
+ }
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(fp);
+ fp = temp;
+ php_stream_rewind(fp);
+ compression = PHAR_FILE_COMPRESSED_GZ;
+
+ /* now, start over */
+ test = '\0';
+ continue;
+ } else if (!memcmp(pos, bz_magic, 3)) {
+ php_stream_filter *filter;
+ php_stream *temp;
+
+ /* entire file is bzip-compressed, uncompress to temporary file */
+ if (!(temp = php_stream_fopen_tmpfile())) {
+ MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
+ }
+ php_stream_rewind(fp);
+ filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+ php_stream_filter_append(&temp->writefilters, filter);
+ if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(fp);
+ fp = temp;
+ php_stream_rewind(fp);
+ compression = PHAR_FILE_COMPRESSED_BZ2;
+
+ /* now, start over */
+ test = '\0';
+ continue;
+ }
if (!memcmp(pos, zip_magic, 4)) {
php_stream_close(fp);
return phar_open_zipfile(fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
}
if (got > 512) {
if (phar_is_tar(pos)) {
- return phar_open_tarfile(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
+ php_stream_rewind(fp);
+ return phar_open_tarfile(fp, fname, fname_len, alias, alias_len, options, pphar, compression, error TSRMLS_CC);
}
}
}
if ((pos = strstr(buffer, token)) != NULL) {
halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
- return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, error TSRMLS_CC);
+ return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
}
halt_offset += got;
return FAILURE;
}
- return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL, error TSRMLS_CC);
+ return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL, PHAR_FILE_COMPRESSED_NONE, error TSRMLS_CC);
}
/* }}} */
* user_stub contains either a string, or a resource pointer, if len is a negative length.
* user_stub and len should be both 0 if the default or existing stub should be used
*/
-int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */
+int phar_flush(phar_archive_data *phar, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */
{
static const char newstub[] = "<?php __HALT_COMPILER(); ?>\r\n";
phar_entry_info *entry, *newentry;
}
#if HAVE_PHAR_ZIP
- if (archive->is_zip) {
- return phar_zip_flush(archive, user_stub, len, error TSRMLS_CC);
+ if (phar->is_zip) {
+ return phar_zip_flush(phar, user_stub, len, error TSRMLS_CC);
}
#endif
- if (archive->is_tar) {
- return phar_tar_flush(archive, user_stub, len, error TSRMLS_CC);
+ if (phar->is_tar) {
+ return phar_tar_flush(phar, user_stub, len, error TSRMLS_CC);
}
- if (archive->fp && !archive->is_brandnew) {
- oldfile = archive->fp;
+ if (phar->fp && !phar->is_brandnew) {
+ oldfile = phar->fp;
closeoldfile = 0;
php_stream_rewind(oldfile);
} else {
- oldfile = php_stream_open_wrapper(archive->fname, "rb", 0, NULL);
+ oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
closeoldfile = oldfile != NULL;
}
newfile = php_stream_fopen_tmpfile();
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "illegal stub for phar \"%s\"", archive->fname);
+ spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
}
if (free_user_stub) {
efree(user_stub);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
}
if (free_user_stub) {
efree(user_stub);
}
return EOF;
}
- archive->halt_offset = len + 5;
+ phar->halt_offset = len + 5;
if (free_user_stub) {
efree(user_stub);
}
} else {
- if (archive->halt_offset && oldfile && !archive->is_brandnew) {
- if (archive->halt_offset != php_stream_copy_to_stream(oldfile, newfile, archive->halt_offset)) {
+ if (phar->halt_offset && oldfile && !phar->is_brandnew) {
+ if (phar->halt_offset != php_stream_copy_to_stream(oldfile, newfile, phar->halt_offset)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
}
return EOF;
}
} else {
/* this is a brand new phar */
- archive->halt_offset = sizeof(newstub)-1;
+ phar->halt_offset = sizeof(newstub)-1;
if (sizeof(newstub)-1 != php_stream_write(newfile, newstub, sizeof(newstub)-1)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to create stub in new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
}
return EOF;
}
/* Check whether we can get rid of some of the deleted entries which are
* unused. However some might still be in use so even after this clean-up
* we need to skip entries marked is_deleted. */
- zend_hash_apply(&archive->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
+ zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
/* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
main_metadata_str.c = 0;
- if (archive->metadata) {
+ if (phar->metadata) {
PHP_VAR_SERIALIZE_INIT(metadata_hash);
- php_var_serialize(&main_metadata_str, &archive->metadata, &metadata_hash TSRMLS_CC);
+ php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
} else {
main_metadata_str.len = 0;
new_manifest_count = 0;
offset = 0;
buf = (char *) emalloc(8192);
- for (zend_hash_internal_pointer_reset(&archive->manifest);
- zend_hash_has_more_elements(&archive->manifest) == SUCCESS;
- zend_hash_move_forward(&archive->manifest)) {
- if (zend_hash_get_current_data(&archive->manifest, (void **)&entry) == FAILURE) {
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
if (entry->cfp) {
if (oldfile && !entry->is_modified) {
continue;
}
- if (!entry->fp || (entry->is_modified && entry->fp == archive->fp)) {
+ if (!entry->fp || (entry->is_modified && entry->fp == phar->fp)) {
/* re-open internal file pointer just-in-time */
- newentry = phar_open_jit(archive, entry, oldfile, error, 0 TSRMLS_CC);
+ newentry = phar_open_jit(phar, entry, oldfile, error, 0 TSRMLS_CC);
if (!newentry) {
/* major problem re-opening, so we ignore this file and the error */
efree(*error);
entry = newentry;
}
file = entry->fp;
- if (file == archive->fp) {
- if (-1 == php_stream_seek(file, entry->offset_within_phar + archive->internal_file_start, SEEK_SET)) {
+ if (file == phar->fp) {
+ if (-1 == php_stream_seek(file, entry->offset_within_phar + phar->internal_file_start, SEEK_SET)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
php_stream_close(newfile);
if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
if (error) {
- spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
}
} else {
if (error) {
- spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
}
}
efree(buf);
return EOF;
}
php_stream_flush(file);
- if (file == archive->fp) {
- if (-1 == php_stream_seek(file, entry->offset_within_phar + archive->internal_file_start, SEEK_SET)) {
+ if (file == phar->fp) {
+ if (-1 == php_stream_seek(file, entry->offset_within_phar + phar->internal_file_start, SEEK_SET)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
* 4: phar metadata length
* ?: phar metadata
*/
- restore_alias_len = archive->alias_len;
- if (!archive->is_explicit_alias) {
- archive->alias_len = 0;
+ restore_alias_len = phar->alias_len;
+ if (!phar->is_explicit_alias) {
+ phar->alias_len = 0;
}
- manifest_len = offset + archive->alias_len + sizeof(manifest) + main_metadata_str.len;
+ manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
phar_set_32(manifest, manifest_len);
phar_set_32(manifest+4, new_manifest_count);
*(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
*(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
phar_set_32(manifest+10, global_flags);
- phar_set_32(manifest+14, archive->alias_len);
+ phar_set_32(manifest+14, phar->alias_len);
/* write the manifest header */
if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
- || (size_t)archive->alias_len != php_stream_write(newfile, archive->alias, archive->alias_len)) {
+ || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
- archive->alias_len = restore_alias_len;
+ phar->alias_len = restore_alias_len;
if (error) {
- spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
}
return EOF;
}
- archive->alias_len = restore_alias_len;
+ phar->alias_len = restore_alias_len;
phar_set_32(manifest, main_metadata_str.len);
if (main_metadata_str.len) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
- archive->alias_len = restore_alias_len;
+ phar->alias_len = restore_alias_len;
if (error) {
- spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
}
return EOF;
}
php_stream_close(oldfile);
}
php_stream_close(newfile);
- archive->alias_len = restore_alias_len;
+ phar->alias_len = restore_alias_len;
if (error) {
- spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
}
return EOF;
}
manifest_ftell = php_stream_tell(newfile);
/* now write the manifest */
- for (zend_hash_internal_pointer_reset(&archive->manifest);
- zend_hash_has_more_elements(&archive->manifest) == SUCCESS;
- zend_hash_move_forward(&archive->manifest)) {
- if (zend_hash_get_current_data(&archive->manifest, (void **)&entry) == FAILURE) {
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
if (entry->is_deleted) {
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
/* now copy the actual file data to the new phar */
offset = 0;
- for (zend_hash_internal_pointer_reset(&archive->manifest);
- zend_hash_has_more_elements(&archive->manifest) == SUCCESS;
- zend_hash_move_forward(&archive->manifest)) {
- if (zend_hash_get_current_data(&archive->manifest, (void **)&entry) == FAILURE) {
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
if (entry->is_deleted) {
php_stream_rewind(file);
} else if (entry->fp && (entry->is_modified || !oldfile)) {
file = entry->fp;
- if (file == archive->fp) {
- if (-1 == php_stream_seek(file, entry->offset_within_phar + archive->internal_file_start, SEEK_SET)) {
+ if (file == phar->fp) {
+ if (-1 == php_stream_seek(file, entry->offset_within_phar + phar->internal_file_start, SEEK_SET)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
- if (-1 == php_stream_seek(oldfile, entry->offset_within_phar + archive->internal_file_start, SEEK_SET)) {
+ if (-1 == php_stream_seek(oldfile, entry->offset_within_phar + phar->internal_file_start, SEEK_SET)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
}
entry->cfp = 0;
}
if (entry->fp && entry->fp_refcount == 0) {
- if (entry->fp != archive->fp) {
+ if (entry->fp != phar->fp) {
php_stream_close(entry->fp);
}
entry->fp = 0;
php_stream_rewind(newfile);
- if (archive->signature) {
- efree(archive->signature);
+ if (phar->signature) {
+ efree(phar->signature);
}
- switch(archive->sig_flags) {
+ switch(phar->sig_flags) {
#if HAVE_HASH_EXT
case PHAR_SIG_SHA512: {
unsigned char digest[64];
PHP_SHA512Final(digest, &context);
php_stream_write(newfile, (char *) digest, sizeof(digest));
sig_flags |= PHAR_SIG_SHA512;
- archive->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &archive->signature);
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
break;
}
case PHAR_SIG_SHA256: {
PHP_SHA256Final(digest, &context);
php_stream_write(newfile, (char *) digest, sizeof(digest));
sig_flags |= PHAR_SIG_SHA256;
- archive->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &archive->signature);
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
break;
}
#else
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
}
return EOF;
#endif
PHP_SHA1Final(digest, &context);
php_stream_write(newfile, (char *) digest, sizeof(digest));
sig_flags |= PHAR_SIG_SHA1;
- archive->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &archive->signature);
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
break;
}
case PHAR_SIG_MD5: {
PHP_MD5Final(digest, &context);
php_stream_write(newfile, (char *) digest, sizeof(digest));
sig_flags |= PHAR_SIG_MD5;
- archive->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &archive->signature);
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
break;
}
}
phar_set_32(sig_buf, sig_flags);
php_stream_write(newfile, sig_buf, 4);
php_stream_write(newfile, "GBMB", 4);
- archive->sig_flags = sig_flags;
+ phar->sig_flags = sig_flags;
}
/* finally, close the temp file, rename the original phar,
move the temp to the old phar, unlink the old phar, and reload it into memory
*/
- if (archive->fp) {
- php_stream_close(archive->fp);
+ if (phar->fp) {
+ php_stream_close(phar->fp);
}
if (closeoldfile) {
php_stream_close(oldfile);
}
- archive->internal_file_start = halt_offset + manifest_len + 4;
- archive->is_brandnew = 0;
+ phar->internal_file_start = halt_offset + manifest_len + 4;
+ phar->is_brandnew = 0;
php_stream_rewind(newfile);
- if (archive->donotflush) {
+ if (phar->donotflush) {
/* deferred flush */
- archive->fp = newfile;
+ phar->fp = newfile;
} else {
- archive->fp = php_stream_open_wrapper(archive->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
- if (!archive->fp) {
- archive->fp = newfile;
+ phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!phar->fp) {
+ phar->fp = newfile;
if (error) {
- spprintf(error, 0, "unable to open new phar \"%s\" for writing", archive->fname);
+ spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname);
}
return EOF;
}
- php_stream_copy_to_stream(newfile, archive->fp, PHP_STREAM_COPY_ALL);
- php_stream_close(newfile);
- /* we could also reopen the file in "rb" mode but there is no need for that */
+ if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
+ php_stream_filter *filter;
+ /* to properly compress, we have to tell zlib to add a zlib header */
+ zval filterparams;
+
+ array_init(&filterparams);
+ add_assoc_long(&filterparams, "window", MAX_WBITS);
+ filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ zval_dtor(&filterparams);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
+ php_stream_filter *filter;
+
+ filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else {
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ /* we could also reopen the file in "rb" mode but there is no need for that */
+ php_stream_close(newfile);
+ }
}
- if (-1 == php_stream_seek(archive->fp, archive->halt_offset, SEEK_SET)) {
+ if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
if (error) {
- spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
}
return EOF;
}
return FAILURE;
}
-int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
{
char buf[512], *actual_alias = NULL;
phar_entry_info entry = {0};
if (error) {
*error = NULL;
}
- php_stream_seek(fp, 0, SEEK_SET);
read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) {
zend_hash_init(&myphar->manifest, sizeof(phar_entry_info),
zend_get_hash_value, destroy_phar_manifest_entry, 0);
myphar->is_tar = 1;
+ /* remember whether this entire phar was compressed with gz/bzip2 */
+ myphar->flags = compression;
entry.is_tar = 1;
entry.is_crc_checked = 1;
return ZEND_HASH_APPLY_KEEP;
}
-int phar_tar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */
+int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */
{
phar_entry_info entry = {0};
static const char newstub[] = "<?php // tar-based phar archive stub file\n__HALT_COMPILER();";
entry.is_crc_checked = 1;
entry.is_tar = 1;
entry.tar_type = '0';
- entry.phar = archive;
+ entry.phar = phar;
/* set alias */
- if (archive->is_explicit_alias) {
+ if (phar->is_explicit_alias) {
entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
entry.filename_len = sizeof(".phar/alias.txt")-1;
entry.fp = php_stream_fopen_tmpfile();
- entry.crc32 = phar_tar_checksum(archive->alias, archive->alias_len);
- php_stream_write(entry.fp, archive->alias, archive->alias_len);
- entry.uncompressed_filesize = archive->alias_len;
- zend_hash_update(&archive->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ entry.crc32 = phar_tar_checksum(phar->alias, phar->alias_len);
+ php_stream_write(entry.fp, phar->alias, phar->alias_len);
+ entry.uncompressed_filesize = phar->alias_len;
+ zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
}
/* set stub */
/* resource passed in */
if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
if (error) {
- spprintf(error, 0, "unable to access resource to copy stub to new tar-based phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to access resource to copy stub to new tar-based phar \"%s\"", phar->fname);
}
return EOF;
}
user_stub = 0;
if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
if (error) {
- spprintf(error, 0, "unable to read resource to copy stub to new tar-based phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to read resource to copy stub to new tar-based phar \"%s\"", phar->fname);
}
return EOF;
}
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{
if (error) {
- spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", archive->fname);
+ spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname);
}
if (free_user_stub) {
efree(user_stub);
if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
|| 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
if (error) {
- spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname);
}
if (free_user_stub) {
efree(user_stub);
}
entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
entry.filename_len = sizeof(".phar/stub.php")-1;
- zend_hash_update(&archive->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
if (free_user_stub) {
efree(user_stub);
}
} else {
- if (!zend_hash_exists(&archive->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
+ if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
/* this is a brand new phar */
entry.fp = php_stream_fopen_tmpfile();
if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
if (error) {
- spprintf(error, 0, "unable to create stub in new tar-based phar \"%s\"", archive->fname);
+ spprintf(error, 0, "unable to create stub in new tar-based phar \"%s\"", phar->fname);
}
return EOF;
}
entry.uncompressed_filesize = sizeof(newstub) - 1;
entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
entry.filename_len = sizeof(".phar/stub.php")-1;
- zend_hash_add(&archive->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
}
}
- if (archive->fp && !archive->is_brandnew) {
- oldfile = archive->fp;
+ if (phar->fp && !phar->is_brandnew) {
+ oldfile = phar->fp;
closeoldfile = 0;
php_stream_rewind(oldfile);
} else {
- oldfile = php_stream_open_wrapper(archive->fname, "rb", 0, NULL);
+ oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
closeoldfile = oldfile != NULL;
}
newfile = php_stream_fopen_tmpfile();
pass.new = newfile;
pass.error = error;
- zend_hash_apply_with_argument(&archive->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
+ zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
/* add final zero blocks */
buf = (char *) ecalloc(1024, 1);
php_stream_close(newfile);
return EOF;
}
- if (archive->fp) {
- php_stream_close(archive->fp);
+ if (phar->fp) {
+ php_stream_close(phar->fp);
}
- archive->is_brandnew = 0;
+ phar->is_brandnew = 0;
php_stream_rewind(newfile);
- if (archive->donotflush) {
+ if (phar->donotflush) {
/* deferred flush */
- archive->fp = newfile;
+ phar->fp = newfile;
} else {
- archive->fp = php_stream_open_wrapper(archive->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
- if (!archive->fp) {
- archive->fp = newfile;
+
+ phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!phar->fp) {
+ phar->fp = newfile;
if (error) {
- spprintf(error, 0, "unable to open new phar \"%s\" for writing", archive->fname);
+ spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname);
}
return EOF;
}
- php_stream_copy_to_stream(newfile, archive->fp, PHP_STREAM_COPY_ALL);
- php_stream_close(newfile);
- /* we could also reopen the file in "rb" mode but there is no need for that */
+ if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
+ php_stream_filter *filter;
+ /* to properly compress, we have to tell zlib to add a zlib header */
+ zval filterparams;
+
+ array_init(&filterparams);
+ add_assoc_long(&filterparams, "window", MAX_WBITS);
+ filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ zval_dtor(&filterparams);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
+ php_stream_filter *filter;
+
+ filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else {
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ /* we could also reopen the file in "rb" mode but there is no need for that */
+ php_stream_close(newfile);
+ }
}
return EOF;
}