- ws/cs, macros, code that only affects other branches

- some unsynced changes need valgrind testing before they can go into this branch, see PECL/HEAD
This commit is contained in:
Steph Fox 2008-08-01 13:48:45 +00:00
parent 821bab83a3
commit 4e5280a7a2
18 changed files with 1852 additions and 817 deletions

View file

@ -5,14 +5,12 @@
* @ingroup Phar * @ingroup Phar
* @brief class Phar Pre Command * @brief class Phar Pre Command
* @author Marcus Boerger * @author Marcus Boerger
* @date 2007 - 2007 * @date 2007 - 2008
* *
* Phar Command * Phar Command
*/ */
foreach(array("SPL", "Reflection", "Phar") as $ext) foreach(array("SPL", "Reflection", "Phar") as $ext) {
{ if (!extension_loaded($ext)) {
if (!extension_loaded($ext))
{
echo "$argv[0] requires PHP extension $ext.\n"; echo "$argv[0] requires PHP extension $ext.\n";
exit(1); exit(1);
} }
@ -28,14 +26,12 @@ $classes = array(
'PharCommand', 'PharCommand',
); );
foreach($classes as $name) foreach($classes as $name) {
{
echo "if (!class_exists('$name', 0))\n{\n"; echo "if (!class_exists('$name', 0))\n{\n";
$f = file(dirname(__FILE__) . '/phar/' . strtolower($name) . '.inc'); $f = file(dirname(__FILE__) . '/phar/' . strtolower($name) . '.inc');
unset($f[0]); unset($f[0]);
$c = count($f); $c = count($f);
while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) {
{
unset($f[$c--]); unset($f[$c--]);
} }
if (substr($f[$c], -2) == "\r\n") { if (substr($f[$c], -2) == "\r\n") {
@ -47,8 +43,7 @@ foreach($classes as $name)
if (substr($f[$c], -2) == '?>') { if (substr($f[$c], -2) == '?>') {
$f[$c] = substr($f[$c], 0,-2); $f[$c] = substr($f[$c], 0,-2);
} }
while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) {
{
unset($f[$c--]); unset($f[$c--]);
} }
echo join('', $f); echo join('', $f);

View file

@ -45,13 +45,13 @@ static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{
{ {
HashTable *data = (HashTable *)stream->abstract; HashTable *data = (HashTable *)stream->abstract;
if (data && data->arBuckets) if (data && data->arBuckets) {
{
zend_hash_destroy(data); zend_hash_destroy(data);
data->arBuckets = 0; data->arBuckets = 0;
FREE_HASHTABLE(data); FREE_HASHTABLE(data);
stream->abstract = NULL; stream->abstract = NULL;
} }
return 0; return 0;
} }
/* }}} */ /* }}} */
@ -63,14 +63,15 @@ static int phar_dir_seek(php_stream *stream, off_t offset, int whence, off_t *ne
{ {
HashTable *data = (HashTable *)stream->abstract; HashTable *data = (HashTable *)stream->abstract;
if (!data) if (!data) {
{
return -1; return -1;
} }
if (whence == SEEK_END) { if (whence == SEEK_END) {
whence = SEEK_SET; whence = SEEK_SET;
offset = zend_hash_num_elements(data) + offset; offset = zend_hash_num_elements(data) + offset;
} }
if (whence == SEEK_SET) { if (whence == SEEK_SET) {
zend_hash_internal_pointer_reset(data); zend_hash_internal_pointer_reset(data);
} }
@ -102,15 +103,19 @@ static size_t phar_dir_read(php_stream *stream, char *buf, size_t count TSRMLS_D
if (FAILURE == zend_hash_has_more_elements(data)) { if (FAILURE == zend_hash_has_more_elements(data)) {
return 0; return 0;
} }
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) { if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) {
return 0; return 0;
} }
PHAR_STR(key, str_key); PHAR_STR(key, str_key);
zend_hash_move_forward(data); zend_hash_move_forward(data);
to_read = MIN(keylen, count); to_read = MIN(keylen, count);
if (to_read == 0 || count < keylen) { if (to_read == 0 || count < keylen) {
return 0; return 0;
} }
memset(buf, 0, sizeof(php_stream_dirent)); memset(buf, 0, sizeof(php_stream_dirent));
memcpy(((php_stream_dirent *) buf)->d_name, str_key, to_read); memcpy(((php_stream_dirent *) buf)->d_name, str_key, to_read);
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0'; ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
@ -159,10 +164,9 @@ static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC) /* {{{
Bucket *f; Bucket *f;
Bucket *s; Bucket *s;
int result; int result;
f = *((Bucket **) a); f = *((Bucket **) a);
s = *((Bucket **) b); s = *((Bucket **) b);
#if (PHP_MAJOR_VERSION < 6) #if (PHP_MAJOR_VERSION < 6)
result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength); result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
#else #else
@ -202,12 +206,16 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
efree(dir); efree(dir);
return php_stream_alloc(&phar_dir_ops, data, NULL, "r"); return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
} }
zend_hash_internal_pointer_reset(manifest); zend_hash_internal_pointer_reset(manifest);
while (FAILURE != zend_hash_has_more_elements(manifest)) { while (FAILURE != zend_hash_has_more_elements(manifest)) {
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) { if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
break; break;
} }
PHAR_STR(key, str_key); PHAR_STR(key, str_key);
if (keylen <= (uint)dirlen) { if (keylen <= (uint)dirlen) {
if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) { if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
if (SUCCESS != zend_hash_move_forward(manifest)) { if (SUCCESS != zend_hash_move_forward(manifest)) {
@ -216,6 +224,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
continue; continue;
} }
} }
if (*dir == '/') { if (*dir == '/') {
/* root directory */ /* root directory */
if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) { if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
@ -225,6 +234,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
} }
continue; continue;
} }
if (NULL != (found = (char *) memchr(str_key, '/', keylen))) { if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
/* the entry has a path separator and is a subdirectory */ /* the entry has a path separator and is a subdirectory */
entry = (char *) safe_emalloc(found - str_key, 1, 1); entry = (char *) safe_emalloc(found - str_key, 1, 1);
@ -236,6 +246,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
memcpy(entry, str_key, keylen); memcpy(entry, str_key, keylen);
entry[keylen] = '\0'; entry[keylen] = '\0';
} }
goto PHAR_ADD_ENTRY; goto PHAR_ADD_ENTRY;
} else { } else {
if (0 != memcmp(str_key, dir, dirlen)) { if (0 != memcmp(str_key, dir, dirlen)) {
@ -253,8 +264,10 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
} }
} }
} }
save = str_key; save = str_key;
save += dirlen + 1; /* seek to just past the path separator */ save += dirlen + 1; /* seek to just past the path separator */
if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) { if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
/* is subdirectory */ /* is subdirectory */
save -= dirlen + 1; save -= dirlen + 1;
@ -274,11 +287,14 @@ PHAR_ADD_ENTRY:
if (keylen) { if (keylen) {
phar_add_empty(data, entry, keylen); phar_add_empty(data, entry, keylen);
} }
efree(entry); efree(entry);
if (SUCCESS != zend_hash_move_forward(manifest)) { if (SUCCESS != zend_hash_move_forward(manifest)) {
break; break;
} }
} }
if (FAILURE != zend_hash_has_more_elements(data)) { if (FAILURE != zend_hash_has_more_elements(data)) {
efree(dir); efree(dir);
if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) { if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
@ -296,8 +312,7 @@ PHAR_ADD_ENTRY:
/** /**
* Open a directory handle within a phar archive * Open a directory handle within a phar archive
*/ */
php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
{ {
php_url *resource = NULL; php_url *resource = NULL;
php_stream *ret; php_stream *ret;
@ -334,8 +349,8 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char
host_len = strlen(resource->host); host_len = strlen(resource->host);
phar_request_initialize(TSRMLS_C); phar_request_initialize(TSRMLS_C);
internal_file = resource->path + 1; /* strip leading "/" */ internal_file = resource->path + 1; /* strip leading "/" */
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
if (error) { if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
@ -346,9 +361,11 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char
php_url_free(resource); php_url_free(resource);
return NULL; return NULL;
} }
if (error) { if (error) {
efree(error); efree(error);
} }
if (*internal_file == '\0') { if (*internal_file == '\0') {
/* root directory requested */ /* root directory requested */
internal_file = estrndup(internal_file - 1, 1); internal_file = estrndup(internal_file - 1, 1);
@ -356,10 +373,12 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char
php_url_free(resource); php_url_free(resource);
return ret; return ret;
} }
if (!phar->manifest.arBuckets) { if (!phar->manifest.arBuckets) {
php_url_free(resource); php_url_free(resource);
return NULL; return NULL;
} }
if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) { if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) {
php_url_free(resource); php_url_free(resource);
return NULL; return NULL;
@ -389,6 +408,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char
return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
} }
} }
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
break; break;
} }
@ -417,11 +437,14 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
return 0; return 0;
} }
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) { if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL; phar = NULL;
} }
efree(arch); efree(arch);
efree(entry2); efree(entry2);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) { if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
return 0; return 0;
@ -463,18 +486,21 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
php_url_free(resource); php_url_free(resource);
return 0; return 0;
} }
if (error) { if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
efree(error); efree(error);
php_url_free(resource); php_url_free(resource);
return 0; return 0;
} }
if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC))) { if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC))) {
/* entry exists as a file */ /* entry exists as a file */
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
php_url_free(resource); php_url_free(resource);
return 0; return 0;
} }
if (error) { if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
efree(error); efree(error);
@ -494,11 +520,14 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
if (phar->is_zip) { if (phar->is_zip) {
entry.is_zip = 1; entry.is_zip = 1;
} }
entry.filename = estrdup(resource->path + 1); entry.filename = estrdup(resource->path + 1);
if (phar->is_tar) { if (phar->is_tar) {
entry.is_tar = 1; entry.is_tar = 1;
entry.tar_type = TAR_DIR; entry.tar_type = TAR_DIR;
} }
entry.filename_len = strlen(resource->path + 1); entry.filename_len = strlen(resource->path + 1);
php_url_free(resource); php_url_free(resource);
entry.is_dir = 1; entry.is_dir = 1;
@ -507,19 +536,23 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
entry.is_crc_checked = 1; entry.is_crc_checked = 1;
entry.flags = PHAR_ENT_PERM_DEF_DIR; entry.flags = PHAR_ENT_PERM_DEF_DIR;
entry.old_flags = PHAR_ENT_PERM_DEF_DIR; entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname);
efree(error); efree(error);
efree(entry.filename); efree(entry.filename);
return 0; return 0;
} }
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
if (error) { if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
zend_hash_del(&phar->manifest, entry.filename, entry.filename_len); zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
efree(error); efree(error);
return 0; return 0;
} }
phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC); phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC);
return 1; return 1;
} }
@ -547,11 +580,14 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
return 0; return 0;
} }
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) { if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL; phar = NULL;
} }
efree(arch); efree(arch);
efree(entry2); efree(entry2);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) { if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
return 0; return 0;
@ -584,7 +620,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
} }
path_len = strlen(resource->path+1); path_len = strlen(resource->path+1);
if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1 TSRMLS_CC))) { if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1 TSRMLS_CC))) {
if (error) { if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
@ -604,13 +640,13 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
} }
for (zend_hash_internal_pointer_reset(&phar->manifest); for (zend_hash_internal_pointer_reset(&phar->manifest);
HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)); HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL));
zend_hash_move_forward(&phar->manifest)) { zend_hash_move_forward(&phar->manifest)) {
if (!entry->is_deleted && if (!entry->is_deleted &&
key_len > path_len && key_len > path_len &&
memcmp(key, resource->path+1, path_len) == 0 && memcmp(key, resource->path+1, path_len) == 0 &&
IS_SLASH(key[path_len])) { IS_SLASH(key[path_len])) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty"); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
if (entry->is_temp_dir) { if (entry->is_temp_dir) {
efree(entry->filename); efree(entry->filename);
@ -622,13 +658,13 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
} }
for (zend_hash_internal_pointer_reset(&phar->virtual_dirs); for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL)); HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
zend_hash_move_forward(&phar->virtual_dirs)) { zend_hash_move_forward(&phar->virtual_dirs)) {
if (!entry->is_deleted && if (!entry->is_deleted &&
key_len > path_len && key_len > path_len &&
memcmp(key, resource->path+1, path_len) == 0 && memcmp(key, resource->path+1, path_len) == 0 &&
IS_SLASH(key[path_len])) { IS_SLASH(key[path_len])) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty"); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
if (entry->is_temp_dir) { if (entry->is_temp_dir) {
efree(entry->filename); efree(entry->filename);

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group | | Copyright (c) 2006-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

View file

@ -37,6 +37,7 @@ PHAR_FUNC(phar_opendir) /* {{{ */
&& !cached_phars.arBuckets) { && !cached_phars.arBuckets) {
goto skip_phar; goto skip_phar;
} }
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
return; return;
} }
@ -110,10 +111,12 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
&& !cached_phars.arBuckets) { && !cached_phars.arBuckets) {
goto skip_phar; goto skip_phar;
} }
/* Parse arguments */ /* Parse arguments */
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) { if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
goto skip_phar; goto skip_phar;
} }
if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
char *arch, *entry, *fname; char *arch, *entry, *fname;
int arch_len, entry_len, fname_len; int arch_len, entry_len, fname_len;
@ -783,7 +786,7 @@ statme_baby:
if (!phar->is_writeable) { if (!phar->is_writeable) {
sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777); sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
} }
sb.st_nlink = 1; sb.st_nlink = 1;
sb.st_rdev = -1; sb.st_rdev = -1;
/* this is only for APC, so use /dev/null device - no chance of conflict there! */ /* this is only for APC, so use /dev/null device - no chance of conflict there! */

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group | | Copyright (c) 2006-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

View file

@ -34,7 +34,7 @@ $stub = '/*
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension generated stub | | phar php single-file executable PHP extension generated stub |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2005-' . date('Y') . ' The PHP Group | | Copyright (c) 2005-' . date('Y') . ' The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group | | Copyright (c) 2006-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |
@ -163,7 +163,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phar)
int has_bz2; int has_bz2;
zend_bool readonly_orig; zend_bool readonly_orig;
zend_bool require_hash_orig; zend_bool require_hash_orig;
zend_bool intercepted; zend_bool intercepted;
int request_init; int request_init;
int require_hash; int require_hash;
int request_done; int request_done;
@ -493,8 +493,8 @@ union _phar_archive_object {
zend_object std; zend_object std;
spl_filesystem_object spl; spl_filesystem_object spl;
struct { struct {
zend_object std; zend_object std;
phar_archive_data *archive; phar_archive_data *archive;
} arc; } arc;
}; };
#endif #endif
@ -505,8 +505,8 @@ union _phar_entry_object {
zend_object std; zend_object std;
spl_filesystem_object spl; spl_filesystem_object spl;
struct { struct {
zend_object std; zend_object std;
phar_entry_info *entry; phar_entry_info *entry;
} ent; } ent;
}; };
#endif #endif
@ -520,11 +520,15 @@ extern char *(*phar_save_resolve_path)(const char *filename, int filename_len TS
#if PHP_VERSION_ID >= 60000 #if PHP_VERSION_ID >= 60000
typedef zstr phar_zstr; typedef zstr phar_zstr;
#define PHAR_STR(a, b) \ #define PHAR_STR(a, b) \
spprintf(&b, 0, "%r", a.s); spprintf(&b, 0, "%s", a.s);
#define PHAR_ZSTR(a, b) \
b = ZSTR(a);
#else #else
typedef char *phar_zstr; typedef char *phar_zstr;
#define PHAR_STR(a, b) \ #define PHAR_STR(a, b) \
b = a; b = a;
#define PHAR_ZSTR(a, b) \
b = a;
#endif #endif
BEGIN_EXTERN_C() BEGIN_EXTERN_C()

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2007 The PHP Group | | Copyright (c) 2007-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2007 The PHP Group | | Copyright (c) 2007-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2005 The PHP Group | | Copyright (c) 2005-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |
@ -22,7 +22,7 @@
#ifndef PHP_PHAR_H #ifndef PHP_PHAR_H
#define PHP_PHAR_H #define PHP_PHAR_H
#define PHP_PHAR_VERSION "2.0.0b2-dev" #define PHP_PHAR_VERSION "2.0.0b2-dev"
#include "ext/standard/basic_functions.h" #include "ext/standard/basic_functions.h"
extern zend_module_entry phar_module_entry; extern zend_module_entry phar_module_entry;
@ -34,7 +34,7 @@ extern zend_module_entry phar_module_entry;
#define PHP_PHAR_API #define PHP_PHAR_API
#endif #endif
#endif /* PHP_PHAR_H */ #endif /* PHP_PHAR_H */
/* /*

View file

@ -3,293 +3,293 @@
$web = '000'; $web = '000';
if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
Phar::interceptFileFuncs(); Phar::interceptFileFuncs();
set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
Phar::webPhar(null, $web); Phar::webPhar(null, $web);
include 'phar://' . __FILE__ . '/' . Extract_Phar::START; include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
return; return;
} }
if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
Extract_Phar::go(true); Extract_Phar::go(true);
$mimes = array( $mimes = array(
'phps' => 2, 'phps' => 2,
'c' => 'text/plain', 'c' => 'text/plain',
'cc' => 'text/plain', 'cc' => 'text/plain',
'cpp' => 'text/plain', 'cpp' => 'text/plain',
'c++' => 'text/plain', 'c++' => 'text/plain',
'dtd' => 'text/plain', 'dtd' => 'text/plain',
'h' => 'text/plain', 'h' => 'text/plain',
'log' => 'text/plain', 'log' => 'text/plain',
'rng' => 'text/plain', 'rng' => 'text/plain',
'txt' => 'text/plain', 'txt' => 'text/plain',
'xsd' => 'text/plain', 'xsd' => 'text/plain',
'php' => 1, 'php' => 1,
'inc' => 1, 'inc' => 1,
'avi' => 'video/avi', 'avi' => 'video/avi',
'bmp' => 'image/bmp', 'bmp' => 'image/bmp',
'css' => 'text/css', 'css' => 'text/css',
'gif' => 'image/gif', 'gif' => 'image/gif',
'htm' => 'text/html', 'htm' => 'text/html',
'html' => 'text/html', 'html' => 'text/html',
'htmls' => 'text/html', 'htmls' => 'text/html',
'ico' => 'image/x-ico', 'ico' => 'image/x-ico',
'jpe' => 'image/jpeg', 'jpe' => 'image/jpeg',
'jpg' => 'image/jpeg', 'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg', 'jpeg' => 'image/jpeg',
'js' => 'application/x-javascript', 'js' => 'application/x-javascript',
'midi' => 'audio/midi', 'midi' => 'audio/midi',
'mid' => 'audio/midi', 'mid' => 'audio/midi',
'mod' => 'audio/mod', 'mod' => 'audio/mod',
'mov' => 'movie/quicktime', 'mov' => 'movie/quicktime',
'mp3' => 'audio/mp3', 'mp3' => 'audio/mp3',
'mpg' => 'video/mpeg', 'mpg' => 'video/mpeg',
'mpeg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
'pdf' => 'application/pdf', 'pdf' => 'application/pdf',
'png' => 'image/png', 'png' => 'image/png',
'swf' => 'application/shockwave-flash', 'swf' => 'application/shockwave-flash',
'tif' => 'image/tiff', 'tif' => 'image/tiff',
'tiff' => 'image/tiff', 'tiff' => 'image/tiff',
'wav' => 'audio/wav', 'wav' => 'audio/wav',
'xbm' => 'image/xbm', 'xbm' => 'image/xbm',
'xml' => 'text/xml', 'xml' => 'text/xml',
); );
header("Cache-Control: no-cache, must-revalidate"); header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache"); header("Pragma: no-cache");
$basename = basename(__FILE__); $basename = basename(__FILE__);
if (!strpos($_SERVER['REQUEST_URI'], $basename)) { if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
chdir(Extract_Phar::$temp); chdir(Extract_Phar::$temp);
include $web; include $web;
return; return;
} }
$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); $pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
if (!$pt || $pt == '/') { if (!$pt || $pt == '/') {
$pt = $web; $pt = $web;
header('HTTP/1.1 301 Moved Permanently'); header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
exit; exit;
} }
$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); $a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
header('HTTP/1.0 404 Not Found'); header('HTTP/1.0 404 Not Found');
echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
exit; exit;
} }
$b = pathinfo($a); $b = pathinfo($a);
if (!isset($b['extension'])) { if (!isset($b['extension'])) {
header('Content-Type: text/plain'); header('Content-Type: text/plain');
header('Content-Length: ' . filesize($a)); header('Content-Length: ' . filesize($a));
readfile($a); readfile($a);
exit; exit;
} }
if (isset($mimes[$b['extension']])) { if (isset($mimes[$b['extension']])) {
if ($mimes[$b['extension']] === 1) { if ($mimes[$b['extension']] === 1) {
include $a; include $a;
exit; exit;
} }
if ($mimes[$b['extension']] === 2) { if ($mimes[$b['extension']] === 2) {
highlight_file($a); highlight_file($a);
exit; exit;
} }
header('Content-Type: ' .$mimes[$b['extension']]); header('Content-Type: ' .$mimes[$b['extension']]);
header('Content-Length: ' . filesize($a)); header('Content-Length: ' . filesize($a));
readfile($a); readfile($a);
exit; exit;
} }
} }
class Extract_Phar class Extract_Phar
{ {
static $temp; static $temp;
static $origdir; static $origdir;
const GZ = 0x1000; const GZ = 0x1000;
const BZ2 = 0x2000; const BZ2 = 0x2000;
const MASK = 0x3000; const MASK = 0x3000;
const START = 'index.php'; const START = 'index.php';
const LEN = XXXX; const LEN = XXXX;
static function go($return = false) static function go($return = false)
{ {
$fp = fopen(__FILE__, 'rb'); $fp = fopen(__FILE__, 'rb');
fseek($fp, self::LEN); fseek($fp, self::LEN);
$L = unpack('V', $a = (binary)fread($fp, 4)); $L = unpack('V', $a = (binary)fread($fp, 4));
$m = (binary)''; $m = (binary)'';
do { do {
$read = 8192; $read = 8192;
if ($L[1] - strlen($m) < 8192) { if ($L[1] - strlen($m) < 8192) {
$read = $L[1] - strlen($m); $read = $L[1] - strlen($m);
} }
$last = (binary)fread($fp, $read); $last = (binary)fread($fp, $read);
$m .= $last; $m .= $last;
} while (strlen($last) && strlen($m) < $L[1]); } while (strlen($last) && strlen($m) < $L[1]);
if (strlen($m) < $L[1]) { if (strlen($m) < $L[1]) {
die('ERROR: manifest length read was "' . die('ERROR: manifest length read was "' .
strlen($m) .'" should be "' . strlen($m) .'" should be "' .
$L[1] . '"'); $L[1] . '"');
} }
$info = self::_unpack($m); $info = self::_unpack($m);
$f = $info['c']; $f = $info['c'];
if ($f & self::GZ) { if ($f & self::GZ) {
if (!function_exists('gzinflate')) { if (!function_exists('gzinflate')) {
die('Error: zlib extension is not enabled -' . die('Error: zlib extension is not enabled -' .
' gzinflate() function needed for zlib-compressed .phars'); ' gzinflate() function needed for zlib-compressed .phars');
} }
} }
if ($f & self::BZ2) { if ($f & self::BZ2) {
if (!function_exists('bzdecompress')) { if (!function_exists('bzdecompress')) {
die('Error: bzip2 extension is not enabled -' . die('Error: bzip2 extension is not enabled -' .
' bzdecompress() function needed for bz2-compressed .phars'); ' bzdecompress() function needed for bz2-compressed .phars');
} }
} }
$temp = self::tmpdir(); $temp = self::tmpdir();
if (!$temp || !is_writable($temp)) { if (!$temp || !is_writable($temp)) {
$sessionpath = session_save_path(); $sessionpath = session_save_path();
if (strpos ($sessionpath, ";") !== false) if (strpos ($sessionpath, ";") !== false)
$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); $sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
if (!file_exists($sessionpath) || !is_dir($sessionpath)) { if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
die('Could not locate temporary directory to extract phar'); die('Could not locate temporary directory to extract phar');
} }
$temp = $sessionpath; $temp = $sessionpath;
} }
$temp .= '/pharextract/'.basename(__FILE__, '.phar'); $temp .= '/pharextract/'.basename(__FILE__, '.phar');
self::$temp = $temp; self::$temp = $temp;
self::$origdir = getcwd(); self::$origdir = getcwd();
@mkdir($temp, 0777, true); @mkdir($temp, 0777, true);
$temp = realpath($temp); $temp = realpath($temp);
if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
self::_removeTmpFiles($temp, getcwd()); self::_removeTmpFiles($temp, getcwd());
@mkdir($temp, 0777, true); @mkdir($temp, 0777, true);
@file_put_contents($temp . '/' . md5_file(__FILE__), ''); @file_put_contents($temp . '/' . md5_file(__FILE__), '');
foreach ($info['m'] as $path => $file) { foreach ($info['m'] as $path => $file) {
$a = !file_exists(dirname($temp . '/' . $path)); $a = !file_exists(dirname($temp . '/' . $path));
@mkdir(dirname($temp . '/' . $path), 0777, true); @mkdir(dirname($temp . '/' . $path), 0777, true);
clearstatcache(); clearstatcache();
if ($path[strlen($path) - 1] == '/') { if ($path[strlen($path) - 1] == '/') {
@mkdir($temp . '/' . $path, 0777); @mkdir($temp . '/' . $path, 0777);
} else { } else {
file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
@chmod($temp . '/' . $path, 0666); @chmod($temp . '/' . $path, 0666);
} }
} }
} }
chdir($temp); chdir($temp);
if (!$return) { if (!$return) {
include self::START; include self::START;
} }
} }
static function tmpdir() static function tmpdir()
{ {
if (strpos(PHP_OS, 'WIN') !== false) { if (strpos(PHP_OS, 'WIN') !== false) {
if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
return $var; return $var;
} }
if (is_dir('/temp') || mkdir('/temp')) { if (is_dir('/temp') || mkdir('/temp')) {
return realpath('/temp'); return realpath('/temp');
} }
return false; return false;
} }
if ($var = getenv('TMPDIR')) { if ($var = getenv('TMPDIR')) {
return $var; return $var;
} }
return realpath('/tmp'); return realpath('/tmp');
} }
static function _unpack($m) static function _unpack($m)
{ {
$info = unpack('V', substr($m, 0, 4)); $info = unpack('V', substr($m, 0, 4));
// skip API version, phar flags, alias, metadata // skip API version, phar flags, alias, metadata
$l = unpack('V', substr($m, 10, 4)); $l = unpack('V', substr($m, 10, 4));
$m = substr($m, 14 + $l[1]); $m = substr($m, 14 + $l[1]);
$s = unpack('V', substr($m, 0, 4)); $s = unpack('V', substr($m, 0, 4));
$o = 0; $o = 0;
$start = 4 + $s[1]; $start = 4 + $s[1];
$ret['c'] = 0; $ret['c'] = 0;
for ($i = 0; $i < $info[1]; $i++) { for ($i = 0; $i < $info[1]; $i++) {
// length of the file name // length of the file name
$len = unpack('V', substr($m, $start, 4)); $len = unpack('V', substr($m, $start, 4));
$start += 4; $start += 4;
// file name // file name
$savepath = substr($m, $start, $len[1]); $savepath = substr($m, $start, $len[1]);
$start += $len[1]; $start += $len[1];
// retrieve manifest data: // retrieve manifest data:
// 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags // 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags
// 5 = metadata length // 5 = metadata length
$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] $ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
& 0xffffffff); & 0xffffffff);
$ret['m'][$savepath][7] = $o; $ret['m'][$savepath][7] = $o;
$o += $ret['m'][$savepath][2]; $o += $ret['m'][$savepath][2];
$start += 24 + $ret['m'][$savepath][5]; $start += 24 + $ret['m'][$savepath][5];
$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; $ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
} }
return $ret; return $ret;
} }
static function extractFile($path, $entry, $fp) static function extractFile($path, $entry, $fp)
{ {
$data = ''; $data = '';
$c = $entry[2]; $c = $entry[2];
while ($c) { while ($c) {
if ($c < 8192) { if ($c < 8192) {
$data .= @fread($fp, $c); $data .= @fread($fp, $c);
$c = 0; $c = 0;
} else { } else {
$c -= 8192; $c -= 8192;
$data .= @fread($fp, 8192); $data .= @fread($fp, 8192);
} }
} }
if ($entry[4] & self::GZ) { if ($entry[4] & self::GZ) {
$data = gzinflate($data); $data = gzinflate($data);
} elseif ($entry[4] & self::BZ2) { } elseif ($entry[4] & self::BZ2) {
$data = bzdecompress($data); $data = bzdecompress($data);
} }
if (strlen($data) != $entry[0]) { if (strlen($data) != $entry[0]) {
die("Invalid internal .phar file (size error " . strlen($data) . " != " . die("Invalid internal .phar file (size error " . strlen($data) . " != " .
$stat[7] . ")"); $stat[7] . ")");
} }
if ($entry[3] != sprintf("%u", crc32((binary)$data) & 0xffffffff)) { if ($entry[3] != sprintf("%u", crc32((binary)$data) & 0xffffffff)) {
die("Invalid internal .phar file (checksum error)"); die("Invalid internal .phar file (checksum error)");
} }
return $data; return $data;
} }
static function _removeTmpFiles($temp, $origdir) static function _removeTmpFiles($temp, $origdir)
{ {
chdir($temp); chdir($temp);
foreach (glob('*') as $f) { foreach (glob('*') as $f) {
if (file_exists($f)) { if (file_exists($f)) {
is_dir($f) ? @rmdir($f) : @unlink($f); is_dir($f) ? @rmdir($f) : @unlink($f);
if (file_exists($f) && is_dir($f)) { if (file_exists($f) && is_dir($f)) {
self::_removeTmpFiles($f, getcwd()); self::_removeTmpFiles($f, getcwd());
} }
} }
} }
@rmdir($temp); @rmdir($temp);
clearstatcache(); clearstatcache();
chdir($origdir); chdir($origdir);
} }
} }

View file

@ -35,22 +35,22 @@ php_stream_ops phar_ops = {
}; };
php_stream_wrapper_ops phar_stream_wops = { php_stream_wrapper_ops phar_stream_wops = {
phar_wrapper_open_url, phar_wrapper_open_url,
NULL, /* phar_wrapper_close */ NULL, /* phar_wrapper_close */
NULL, /* phar_wrapper_stat, */ NULL, /* phar_wrapper_stat, */
phar_wrapper_stat, /* stat_url */ phar_wrapper_stat, /* stat_url */
phar_wrapper_open_dir, /* opendir */ phar_wrapper_open_dir, /* opendir */
"phar", "phar",
phar_wrapper_unlink, /* unlink */ phar_wrapper_unlink, /* unlink */
phar_wrapper_rename, /* rename */ phar_wrapper_rename, /* rename */
phar_wrapper_mkdir, /* create directory */ phar_wrapper_mkdir, /* create directory */
phar_wrapper_rmdir, /* remove directory */ phar_wrapper_rmdir, /* remove directory */
}; };
php_stream_wrapper php_stream_phar_wrapper = { php_stream_wrapper php_stream_phar_wrapper = {
&phar_stream_wops, &phar_stream_wops,
NULL, NULL,
0 /* is_url */ 0 /* is_url */
}; };
/** /**
@ -69,8 +69,8 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported"); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported");
} }
return NULL; return NULL;
} }
if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) { if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
if (arch && !entry) { if (arch && !entry) {
@ -147,7 +147,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource); php_url_free(resource);
return NULL; return NULL;
} }
} }
return resource; return resource;
} }
/* }}} */ /* }}} */
@ -296,7 +296,6 @@ idata_error:
} }
} }
php_url_free(resource); php_url_free(resource);
#if MBO_0 #if MBO_0
fprintf(stderr, "Pharname: %s\n", idata->phar->filename); fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
fprintf(stderr, "Filename: %s\n", internal_file); fprintf(stderr, "Filename: %s\n", internal_file);
@ -366,7 +365,7 @@ static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRML
{ {
phar_entry_data *data = (phar_entry_data *)stream->abstract; phar_entry_data *data = (phar_entry_data *)stream->abstract;
size_t got; size_t got;
if (data->internal_file->is_deleted) { if (data->internal_file->is_deleted) {
stream->eof = 1; stream->eof = 1;
return 0; return 0;
@ -379,7 +378,6 @@ static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRML
data->position = php_stream_tell(data->fp) - data->zero; data->position = php_stream_tell(data->fp) - data->zero;
stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize); stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize);
return got; return got;
} }
/* }}} */ /* }}} */
@ -629,7 +627,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
} }
PHAR_STR(key, str_key); PHAR_STR(key, str_key);
if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) { if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
zend_hash_move_forward_ex(&phar->mounted_dirs, &pos); zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue; continue;
} else { } else {
char *test; char *test;
@ -646,7 +644,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen); test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssbi)) { if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
efree(test); efree(test);
zend_hash_move_forward_ex(&phar->mounted_dirs, &pos); zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue; continue;
} }
/* mount the file/directory just in time */ /* mount the file/directory just in time */
@ -664,7 +662,6 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
} }
} }
} }
free_resource: free_resource:
php_url_free(resource); php_url_free(resource);
return FAILURE; return FAILURE;
@ -730,7 +727,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
efree(error); efree(error);
} }
if (idata->internal_file->fp_refcount > 1) { if (idata->internal_file->fp_refcount > 1) {
/* more than just our fp resource is open for this file */ /* more than just our fp resource is open for this file */
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host); php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host);
efree(internal_file); efree(internal_file);
php_url_free(resource); php_url_free(resource);
@ -807,7 +804,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from); php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from);
return 0; return 0;
} }
if (!resource_to->scheme || !resource_to->host || !resource_to->path) { if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
php_url_free(resource_from); php_url_free(resource_from);
php_url_free(resource_to); php_url_free(resource_to);
@ -895,14 +892,14 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
uint to_len = strlen(resource_to->path+1); uint to_len = strlen(resource_to->path+1);
for (zend_hash_internal_pointer_reset(&phar->manifest); for (zend_hash_internal_pointer_reset(&phar->manifest);
HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) && HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) &&
SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry); SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry);
zend_hash_move_forward(&phar->manifest)) { zend_hash_move_forward(&phar->manifest)) {
if (!entry->is_deleted && if (!entry->is_deleted &&
key_len > from_len && key_len > from_len &&
memcmp(key, resource_from->path+1, from_len) == 0 && memcmp(key, resource_from->path+1, from_len) == 0 &&
IS_SLASH(key[from_len])) { IS_SLASH(key[from_len])) {
new_key_len = key_len + to_len - from_len; new_key_len = key_len + to_len - from_len;
new_key = emalloc(new_key_len+1); new_key = emalloc(new_key_len+1);
@ -916,15 +913,15 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
entry->filename_len = new_key_len; entry->filename_len = new_key_len;
zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL); zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL);
} }
} }
for (zend_hash_internal_pointer_reset(&phar->virtual_dirs); for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL)); HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
zend_hash_move_forward(&phar->virtual_dirs)) { zend_hash_move_forward(&phar->virtual_dirs)) {
if (key_len >= from_len && if (key_len >= from_len &&
memcmp(key, resource_from->path+1, from_len) == 0 && memcmp(key, resource_from->path+1, from_len) == 0 &&
(key_len == from_len || IS_SLASH(key[from_len]))) { (key_len == from_len || IS_SLASH(key[from_len]))) {
new_key_len = key_len + to_len - from_len; new_key_len = key_len + to_len - from_len;
new_key = emalloc(new_key_len+1); new_key = emalloc(new_key_len+1);
@ -937,13 +934,13 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
} }
for (zend_hash_internal_pointer_reset(&phar->mounted_dirs); for (zend_hash_internal_pointer_reset(&phar->mounted_dirs);
HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) && HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) &&
SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry); SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry);
zend_hash_move_forward(&phar->mounted_dirs)) { zend_hash_move_forward(&phar->mounted_dirs)) {
if (key_len >= from_len && if (key_len >= from_len &&
memcmp(key, resource_from->path+1, from_len) == 0 && memcmp(key, resource_from->path+1, from_len) == 0 &&
(key_len == from_len || IS_SLASH(key[from_len]))) { (key_len == from_len || IS_SLASH(key[from_len]))) {
new_key_len = key_len + to_len - from_len; new_key_len = key_len + to_len - from_len;
new_key = emalloc(new_key_len+1); new_key = emalloc(new_key_len+1);
@ -969,6 +966,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
php_url_free(resource_from); php_url_free(resource_from);
php_url_free(resource_to); php_url_free(resource_to);
return 1; return 1;
} }
/* }}} */ /* }}} */

View file

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| phar php single-file executable PHP extension | | phar php single-file executable PHP extension |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group | | Copyright (c) 2006-2008 The PHP Group |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, | | This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is | | that is bundled with this package in the file LICENSE, and is |

View file

@ -27,19 +27,19 @@ static php_uint32 phar_tar_number(char *buf, int len) /* {{{ */
while (i < len && buf[i] == ' ') { while (i < len && buf[i] == ' ') {
++i; ++i;
} }
while (i < len &&
buf[i] >= '0' && while (i < len && buf[i] >= '0' && buf[i] <= '7') {
buf[i] <= '7') {
num = num * 8 + (buf[i] - '0'); num = num * 8 + (buf[i] - '0');
++i; ++i;
} }
return num; return num;
} }
/* }}} */ /* }}} */
/* adapted from format_octal() in libarchive /* adapted from format_octal() in libarchive
* *
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2008 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -176,6 +176,7 @@ int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
php_stream_seek(fp, save, SEEK_SET); php_stream_seek(fp, save, SEEK_SET);
return FAILURE; return FAILURE;
} }
if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 && !memcmp(entry->filename, ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1)) { if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 && !memcmp(entry->filename, ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1)) {
entry->phar->metadata = entry->metadata; entry->phar->metadata = entry->metadata;
entry->metadata = NULL; entry->metadata = NULL;
@ -184,6 +185,7 @@ int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
mentry->metadata = entry->metadata; mentry->metadata = entry->metadata;
entry->metadata = NULL; entry->metadata = NULL;
} }
efree(metadata); efree(metadata);
php_stream_seek(fp, save, SEEK_SET); php_stream_seek(fp, save, SEEK_SET);
return SUCCESS; return SUCCESS;
@ -207,6 +209,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
totalsize = php_stream_tell(fp); totalsize = php_stream_tell(fp);
php_stream_seek(fp, 0, SEEK_SET); php_stream_seek(fp, 0, SEEK_SET);
read = php_stream_read(fp, buf, sizeof(buf)); read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) { if (read != sizeof(buf)) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname); spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname);
@ -214,6 +217,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
php_stream_close(fp); php_stream_close(fp);
return FAILURE; return FAILURE;
} }
hdr = (tar_header*)buf; hdr = (tar_header*)buf;
old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0); old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0);
@ -234,6 +238,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
entry.is_crc_checked = 1; entry.is_crc_checked = 1;
entry.phar = myphar; entry.phar = myphar;
pos += sizeof(buf); pos += sizeof(buf);
do { do {
phar_entry_info *newentry; phar_entry_info *newentry;
@ -298,7 +303,9 @@ bail:
return FAILURE; return FAILURE;
} }
} }
read = php_stream_read(fp, buf, sizeof(buf)); read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) { if (read != sizeof(buf)) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
@ -307,16 +314,21 @@ bail:
phar_destroy_phar_data(myphar TSRMLS_CC); phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE; return FAILURE;
} }
hdr = (tar_header*) buf; hdr = (tar_header*) buf;
sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum)); sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) { if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) {
break; break;
} }
if (error) { if (error) {
spprintf(error, 4096, "phar error: \"%s\" has entries after signature, invalid phar", fname); spprintf(error, 4096, "phar error: \"%s\" has entries after signature, invalid phar", fname);
} }
goto bail; goto bail;
} }
if (!old && hdr->prefix[0] != 0) { if (!old && hdr->prefix[0] != 0) {
char name[256]; char name[256];
@ -327,7 +339,9 @@ bail:
} else { } else {
strcat(name, hdr->name); strcat(name, hdr->name);
} }
entry.filename_len = strlen(hdr->prefix) + 100; entry.filename_len = strlen(hdr->prefix) + 100;
if (name[entry.filename_len - 1] == '/') { if (name[entry.filename_len - 1] == '/') {
/* some tar programs store directories with trailing slash */ /* some tar programs store directories with trailing slash */
entry.filename_len--; entry.filename_len--;
@ -336,13 +350,16 @@ bail:
} else { } else {
entry.filename = pestrdup(hdr->name, myphar->is_persistent); entry.filename = pestrdup(hdr->name, myphar->is_persistent);
entry.filename_len = strlen(entry.filename); entry.filename_len = strlen(entry.filename);
if (entry.filename[entry.filename_len - 1] == '/') { if (entry.filename[entry.filename_len - 1] == '/') {
/* some tar programs store directories with trailing slash */ /* some tar programs store directories with trailing slash */
entry.filename[entry.filename_len - 1] = '\0'; entry.filename[entry.filename_len - 1] = '\0';
entry.filename_len--; entry.filename_len--;
} }
} }
phar_add_virtual_dirs(myphar, entry.filename, entry.filename_len TSRMLS_CC); phar_add_virtual_dirs(myphar, entry.filename, entry.filename_len TSRMLS_CC);
if (sum1 != sum2) { if (sum1 != sum2) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename); spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename);
@ -359,13 +376,13 @@ bail:
entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK; entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK;
entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime)); entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime));
entry.is_persistent = myphar->is_persistent; entry.is_persistent = myphar->is_persistent;
#ifndef S_ISDIR #ifndef S_ISDIR
#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
#endif #endif
if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) { if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) {
entry.tar_type = TAR_DIR; entry.tar_type = TAR_DIR;
} }
if (entry.tar_type == TAR_DIR) { if (entry.tar_type == TAR_DIR) {
entry.is_dir = 1; entry.is_dir = 1;
} else { } else {
@ -373,6 +390,7 @@ bail:
} }
entry.link = NULL; entry.link = NULL;
if (entry.tar_type == TAR_LINK) { if (entry.tar_type == TAR_LINK) {
if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) { if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
if (error) { if (error) {
@ -389,7 +407,11 @@ bail:
} }
phar_set_inode(&entry TSRMLS_CC); phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry); zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);
if (entry.is_persistent) ++entry.manifest_pos;
if (entry.is_persistent) {
++entry.manifest_pos;
}
if (entry.filename_len >= sizeof(".phar/.metadata")-1 && !memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) { if (entry.filename_len >= sizeof(".phar/.metadata")-1 && !memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
if (FAILURE == phar_tar_process_metadata(newentry, fp TSRMLS_CC)) { if (FAILURE == phar_tar_process_metadata(newentry, fp TSRMLS_CC)) {
if (error) { if (error) {
@ -400,6 +422,7 @@ bail:
return FAILURE; return FAILURE;
} }
} }
if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
size_t read; size_t read;
/* found explicit alias */ /* found explicit alias */
@ -411,7 +434,9 @@ bail:
phar_destroy_phar_data(myphar TSRMLS_CC); phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE; return FAILURE;
} }
read = php_stream_read(fp, buf, size); read = php_stream_read(fp, buf, size);
if (read == size) { if (read == size) {
buf[size] = '\0'; buf[size] = '\0';
if (!phar_validate_alias(buf, size)) { if (!phar_validate_alias(buf, size)) {
@ -421,13 +446,16 @@ bail:
buf[52] = '.'; buf[52] = '.';
buf[53] = '\0'; buf[53] = '\0';
} }
if (error) { if (error) {
spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname); spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname);
} }
php_stream_close(fp); php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC); phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE; return FAILURE;
} }
actual_alias = pestrndup(buf, size, myphar->is_persistent); actual_alias = pestrndup(buf, size, myphar->is_persistent);
myphar->alias = actual_alias; myphar->alias = actual_alias;
myphar->alias_len = size; myphar->alias_len = size;
@ -436,12 +464,15 @@ bail:
if (error) { if (error) {
spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname); spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname);
} }
php_stream_close(fp); php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC); phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE; return FAILURE;
} }
} }
size = (size+511)&~511; size = (size+511)&~511;
if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) { if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) {
/* this is not good enough - seek succeeds even on truncated tars */ /* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek(fp, size, SEEK_CUR); php_stream_seek(fp, size, SEEK_CUR);
@ -454,7 +485,9 @@ bail:
return FAILURE; return FAILURE;
} }
} }
read = php_stream_read(fp, buf, sizeof(buf)); read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) { if (read != sizeof(buf)) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
@ -488,6 +521,7 @@ bail:
} else { } else {
myphar->is_data = 1; myphar->is_data = 1;
} }
if (p) { if (p) {
myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p); myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p);
if (myphar->ext == p) { if (myphar->ext == p) {
@ -497,7 +531,9 @@ bail:
myphar->ext_len = (myphar->fname + fname_len) - myphar->ext; myphar->ext_len = (myphar->fname + fname_len) - myphar->ext;
} }
} }
phar_request_initialize(TSRMLS_C); phar_request_initialize(TSRMLS_C);
if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) { if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname); spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname);
@ -506,11 +542,14 @@ bail:
phar_destroy_phar_data(myphar TSRMLS_CC); phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE; return FAILURE;
} }
myphar = *actual; myphar = *actual;
if (actual_alias) { if (actual_alias) {
phar_archive_data **fd_ptr; phar_archive_data **fd_ptr;
myphar->is_temporary_alias = 0; myphar->is_temporary_alias = 0;
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void **)&fd_ptr)) { if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void **)&fd_ptr)) {
if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) { if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) {
if (error) { if (error) {
@ -520,6 +559,7 @@ bail:
return FAILURE; return FAILURE;
} }
} }
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL); zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
} else { } else {
phar_archive_data **fd_ptr; phar_archive_data **fd_ptr;
@ -541,11 +581,14 @@ bail:
myphar->alias = pestrndup(myphar->fname, fname_len, myphar->is_persistent); myphar->alias = pestrndup(myphar->fname, fname_len, myphar->is_persistent);
myphar->alias_len = fname_len; myphar->alias_len = fname_len;
} }
myphar->is_temporary_alias = 1; myphar->is_temporary_alias = 1;
} }
if (pphar) { if (pphar) {
*pphar = myphar; *pphar = myphar;
} }
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
@ -569,6 +612,7 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
if (entry->is_mounted) { if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
if (entry->is_deleted) { if (entry->is_deleted) {
if (entry->fp_refcount <= 0) { if (entry->fp_refcount <= 0) {
return ZEND_HASH_APPLY_REMOVE; return ZEND_HASH_APPLY_REMOVE;
@ -579,6 +623,7 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
} }
memset((char *) &header, 0, sizeof(header)); memset((char *) &header, 0, sizeof(header));
if (entry->filename_len > 100) { if (entry->filename_len > 100) {
if (entry->filename_len > 255) { if (entry->filename_len > 255) {
if (fp->error) { if (fp->error) {
@ -591,28 +636,35 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
} else { } else {
memcpy(header.name, entry->filename, entry->filename_len); memcpy(header.name, entry->filename, entry->filename_len);
} }
phar_tar_octal(header.mode, entry->flags & PHAR_ENT_PERM_MASK, sizeof(header.mode)-1); phar_tar_octal(header.mode, entry->flags & PHAR_ENT_PERM_MASK, sizeof(header.mode)-1);
if (FAILURE == phar_tar_octal(header.size, entry->uncompressed_filesize, sizeof(header.size)-1)) { if (FAILURE == phar_tar_octal(header.size, entry->uncompressed_filesize, sizeof(header.size)-1)) {
if (fp->error) { if (fp->error) {
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); 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);
} }
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) { if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) {
if (fp->error) { if (fp->error) {
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); 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);
} }
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
/* calc checksum */ /* calc checksum */
header.typeflag = entry->tar_type; header.typeflag = entry->tar_type;
if (entry->link) { if (entry->link) {
strncpy(header.linkname, entry->link, strlen(entry->link)); strncpy(header.linkname, entry->link, strlen(entry->link));
} }
strncpy(header.magic, "ustar", sizeof("ustar")-1); strncpy(header.magic, "ustar", sizeof("ustar")-1);
strncpy(header.version, "00", sizeof("00")-1); strncpy(header.version, "00", sizeof("00")-1);
strncpy(header.checksum, " ", sizeof(" ")-1); strncpy(header.checksum, " ", sizeof(" ")-1);
entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header)); entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header));
if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) { if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) {
if (fp->error) { if (fp->error) {
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); 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);
@ -622,12 +674,14 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
/* write header */ /* write header */
entry->header_offset = php_stream_tell(fp->new); entry->header_offset = php_stream_tell(fp->new);
if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) { if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) {
if (fp->error) { if (fp->error) {
spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for file \"%s\" could not be written", entry->phar->fname, entry->filename); spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for file \"%s\" could not be written", entry->phar->fname, entry->filename);
} }
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
pos = php_stream_tell(fp->new); /* save start of file within tar */ pos = php_stream_tell(fp->new); /* save start of file within tar */
/* write contents */ /* write contents */
@ -635,22 +689,25 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) { if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) {
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
if (fp->error) { if (fp->error) {
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); 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);
} }
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize)) { if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize)) {
if (fp->error) { if (fp->error) {
spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename); spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename);
} }
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
memset(padding, 0, 512); memset(padding, 0, 512);
php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize); php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
} }
if (!entry->is_modified && entry->fp_refcount) { if (!entry->is_modified && entry->fp_refcount) {
/* open file pointers refer to this fp, do not free the stream */ /* open file pointers refer to this fp, do not free the stream */
switch (entry->fp_type) { switch (entry->fp_type) {
@ -665,12 +722,14 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
} }
entry->is_modified = 0; entry->is_modified = 0;
if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) { if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
if (!entry->fp_refcount) { if (!entry->fp_refcount) {
php_stream_close(entry->fp); php_stream_close(entry->fp);
} }
entry->fp = NULL; entry->fp = NULL;
} }
entry->fp_type = PHAR_FP; entry->fp_type = PHAR_FP;
/* note new location within tar */ /* note new location within tar */
@ -686,24 +745,29 @@ int phar_tar_setmetadata(zval *metadata, phar_entry_info *entry, char **error, p
if (entry->metadata_str.c) { if (entry->metadata_str.c) {
smart_str_free(&entry->metadata_str); smart_str_free(&entry->metadata_str);
} }
entry->metadata_str.c = 0; entry->metadata_str.c = 0;
entry->metadata_str.len = 0; entry->metadata_str.len = 0;
PHP_VAR_SERIALIZE_INIT(metadata_hash); PHP_VAR_SERIALIZE_INIT(metadata_hash);
php_var_serialize(&entry->metadata_str, &metadata, &metadata_hash TSRMLS_CC); php_var_serialize(&entry->metadata_str, &metadata, &metadata_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(metadata_hash); PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
entry->uncompressed_filesize = entry->compressed_filesize = entry->metadata_str.len; entry->uncompressed_filesize = entry->compressed_filesize = entry->metadata_str.len;
if (entry->fp && entry->fp_type == PHAR_MOD) { if (entry->fp && entry->fp_type == PHAR_MOD) {
php_stream_close(entry->fp); php_stream_close(entry->fp);
} }
entry->fp_type = PHAR_MOD; entry->fp_type = PHAR_MOD;
entry->is_modified = 1; entry->is_modified = 1;
entry->fp = php_stream_fopen_tmpfile(); entry->fp = php_stream_fopen_tmpfile();
entry->offset = entry->offset_abs = 0; entry->offset = entry->offset_abs = 0;
if (entry->metadata_str.len != php_stream_write(entry->fp, entry->metadata_str.c, entry->metadata_str.len)) { if (entry->metadata_str.len != php_stream_write(entry->fp, entry->metadata_str.c, entry->metadata_str.len)) {
spprintf(error, 0, "phar tar error: unable to write metadata to magic metadata file \"%s\"", entry->filename); spprintf(error, 0, "phar tar error: unable to write metadata to magic metadata file \"%s\"", entry->filename);
zend_hash_del(&(entry->phar->manifest), entry->filename, entry->filename_len); zend_hash_del(&(entry->phar->manifest), entry->filename, entry->filename_len);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
/* }}} */ /* }}} */
@ -732,13 +796,16 @@ int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC) /* {{{ */
if (!entry->is_modified) { if (!entry->is_modified) {
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
/* now we are dealing with regular files, so look for metadata */ /* now we are dealing with regular files, so look for metadata */
lookfor_len = spprintf(&lookfor, 0, ".phar/.metadata/%s/.metadata.bin", entry->filename); lookfor_len = spprintf(&lookfor, 0, ".phar/.metadata/%s/.metadata.bin", entry->filename);
if (!entry->metadata) { if (!entry->metadata) {
zend_hash_del(&(entry->phar->manifest), lookfor, lookfor_len); zend_hash_del(&(entry->phar->manifest), lookfor, lookfor_len);
efree(lookfor); efree(lookfor);
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
if (SUCCESS == zend_hash_find(&(entry->phar->manifest), lookfor, lookfor_len, (void **)&metadata)) { if (SUCCESS == zend_hash_find(&(entry->phar->manifest), lookfor, lookfor_len, (void **)&metadata)) {
int ret; int ret;
ret = phar_tar_setmetadata(entry->metadata, metadata, error, fp TSRMLS_CC); ret = phar_tar_setmetadata(entry->metadata, metadata, error, fp TSRMLS_CC);
@ -786,6 +853,7 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
if (phar->is_data) { if (phar->is_data) {
goto nostub; goto nostub;
} }
@ -795,13 +863,16 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1); entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
entry.filename_len = sizeof(".phar/alias.txt")-1; entry.filename_len = sizeof(".phar/alias.txt")-1;
entry.fp = php_stream_fopen_tmpfile(); entry.fp = php_stream_fopen_tmpfile();
if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) { if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
if (error) { if (error) {
spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
} }
return EOF; return EOF;
} }
entry.uncompressed_filesize = phar->alias_len; entry.uncompressed_filesize = phar->alias_len;
if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
if (error) { if (error) {
spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
@ -839,8 +910,8 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else { } else {
free_user_stub = 0; free_user_stub = 0;
} }
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{ if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) {
if (error) { if (error) {
spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname); spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname);
} }
@ -849,6 +920,7 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
len = pos - user_stub + 18; len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile(); entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5; entry.uncompressed_filesize = len + 5;
@ -864,9 +936,11 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
php_stream_close(entry.fp); php_stream_close(entry.fp);
return EOF; return EOF;
} }
entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
entry.filename_len = sizeof(".phar/stub.php")-1; entry.filename_len = sizeof(".phar/stub.php")-1;
zend_hash_update(&phar->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) { if (free_user_stub) {
efree(user_stub); efree(user_stub);
} }
@ -911,9 +985,7 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
} }
} }
nostub: nostub:
if (phar->fp && !phar->is_brandnew) { if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp; oldfile = phar->fp;
closeoldfile = 0; closeoldfile = 0;
@ -922,7 +994,9 @@ nostub:
oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL); oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
closeoldfile = oldfile != NULL; closeoldfile = oldfile != NULL;
} }
newfile = php_stream_fopen_tmpfile(); newfile = php_stream_fopen_tmpfile();
if (!newfile) { if (!newfile) {
if (error) { if (error) {
spprintf(error, 0, "unable to create temporary file"); spprintf(error, 0, "unable to create temporary file");
@ -964,6 +1038,7 @@ nostub:
} }
return EOF; return EOF;
} }
if (ZEND_HASH_APPLY_KEEP != phar_tar_setmetadata(phar->metadata, mentry, error, oldfile TSRMLS_CC)) { if (ZEND_HASH_APPLY_KEEP != phar_tar_setmetadata(phar->metadata, mentry, error, oldfile TSRMLS_CC)) {
zend_hash_del(&(phar->manifest), ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1); zend_hash_del(&(phar->manifest), ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1);
if (closeoldfile) { if (closeoldfile) {
@ -973,12 +1048,14 @@ nostub:
} }
} }
} }
zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_setupmetadata, (void *) &pass TSRMLS_CC); zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_setupmetadata, (void *) &pass TSRMLS_CC);
if (error && *error) { if (error && *error) {
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
} }
/* on error in the hash iterator above, error is set */ /* on error in the hash iterator above, error is set */
php_stream_close(newfile); php_stream_close(newfile);
return EOF; return EOF;
@ -994,12 +1071,15 @@ nostub:
spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", save); spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", save);
efree(save); efree(save);
} }
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
} }
php_stream_close(newfile); php_stream_close(newfile);
return EOF; return EOF;
} }
entry.filename = ".phar/signature.bin"; entry.filename = ".phar/signature.bin";
entry.filename_len = sizeof(".phar/signature.bin")-1; entry.filename_len = sizeof(".phar/signature.bin")-1;
entry.fp = php_stream_fopen_tmpfile(); entry.fp = php_stream_fopen_tmpfile();
@ -1008,26 +1088,28 @@ nostub:
# define PHAR_SET_32(var, buffer) \ # define PHAR_SET_32(var, buffer) \
*(php_uint32 *)(var) = (((((unsigned char*)(buffer))[3]) << 24) \ *(php_uint32 *)(var) = (((((unsigned char*)(buffer))[3]) << 24) \
| ((((unsigned char*)(buffer))[2]) << 16) \ | ((((unsigned char*)(buffer))[2]) << 16) \
| ((((unsigned char*)(buffer))[1]) << 8) \ | ((((unsigned char*)(buffer))[1]) << 8) \
| (((unsigned char*)(buffer))[0])) | (((unsigned char*)(buffer))[0]))
#else #else
# define PHAR_SET_32(var, buffer) *(php_uint32 *)(var) = (php_uint32) (buffer) # define PHAR_SET_32(var, buffer) *(php_uint32 *)(var) = (php_uint32) (buffer)
#endif #endif
PHAR_SET_32(sigbuf, phar->sig_flags); PHAR_SET_32(sigbuf, phar->sig_flags);
PHAR_SET_32(sigbuf + 4, signature_length); PHAR_SET_32(sigbuf + 4, signature_length);
if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) { if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) {
efree(signature); efree(signature);
if (error) { if (error) {
spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname); spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname);
} }
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
} }
php_stream_close(newfile); php_stream_close(newfile);
return EOF; return EOF;
} }
efree(signature);
efree(signature);
entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8; entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
/* throw out return value and write the signature */ /* throw out return value and write the signature */
entry.filename_len = phar_tar_writeheaders((void *)&entry, (void *)&pass TSRMLS_CC); entry.filename_len = phar_tar_writeheaders((void *)&entry, (void *)&pass TSRMLS_CC);
@ -1050,14 +1132,17 @@ nostub:
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
} }
/* on error in the hash iterator above, error is set */ /* on error in the hash iterator above, error is set */
if (error && *error) { if (error && *error) {
php_stream_close(newfile); php_stream_close(newfile);
return EOF; return EOF;
} }
if (phar->fp && pass.free_fp) { if (phar->fp && pass.free_fp) {
php_stream_close(phar->fp); php_stream_close(phar->fp);
} }
if (phar->ufp) { if (phar->ufp) {
if (pass.free_ufp) { if (pass.free_ufp) {
php_stream_close(phar->ufp); php_stream_close(phar->ufp);
@ -1066,7 +1151,6 @@ nostub:
} }
phar->is_brandnew = 0; phar->is_brandnew = 0;
php_stream_rewind(newfile); php_stream_rewind(newfile);
if (phar->donotflush) { if (phar->donotflush) {
@ -1081,6 +1165,7 @@ nostub:
} }
return EOF; return EOF;
} }
if (phar->flags & PHAR_FILE_COMPRESSED_GZ) { if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
php_stream_filter *filter; php_stream_filter *filter;
/* to properly compress, we have to tell zlib to add a zlib header */ /* to properly compress, we have to tell zlib to add a zlib header */
@ -1094,6 +1179,7 @@ nostub:
add_assoc_long(&filterparams, "window", MAX_WBITS + 16); add_assoc_long(&filterparams, "window", MAX_WBITS + 16);
filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC); filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
zval_dtor(&filterparams); zval_dtor(&filterparams);
if (!filter) { if (!filter) {
/* copy contents uncompressed rather than lose them */ /* copy contents uncompressed rather than lose them */
php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
@ -1103,6 +1189,7 @@ nostub:
} }
return EOF; return EOF;
} }
php_stream_filter_append(&phar->fp->writefilters, filter); php_stream_filter_append(&phar->fp->writefilters, filter);
php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
php_stream_filter_flush(filter, 1); php_stream_filter_flush(filter, 1);

File diff suppressed because it is too large Load diff

View file

@ -46,30 +46,38 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui
if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) { if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) {
return FAILURE; return FAILURE;
} }
if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') { if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
/* skip to next header */ /* skip to next header */
php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR); php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
len -= PHAR_GET_16(h.header.size) + 4; len -= PHAR_GET_16(h.header.size) + 4;
continue; continue;
} }
/* unix3 header found */ /* unix3 header found */
read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header)); read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
len -= read + 4; len -= read + 4;
if (sizeof(h.unix3) - sizeof(h.header) != read) { if (sizeof(h.unix3) - sizeof(h.header) != read) {
return FAILURE; return FAILURE;
} }
if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) { if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
/* skip symlink filename - we may add this support in later */ /* skip symlink filename - we may add this support in later */
php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR); php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR);
} }
/* set permissions */ /* set permissions */
entry->flags &= PHAR_ENT_COMPRESSION_MASK; entry->flags &= PHAR_ENT_COMPRESSION_MASK;
if (entry->is_dir) { if (entry->is_dir) {
entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK; entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
} else { } else {
entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK; entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
} }
} while (len); } while (len);
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
@ -94,7 +102,7 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui
3. The names of the authors may not be used to endorse or promote 3. The names of the authors may not be used to endorse or promote
products derived from this software without specific prior products derived from this software without specific prior
written permission. written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -109,38 +117,38 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui
*/ */
static time_t phar_zip_d2u_time(int dtime, int ddate) /* {{{ */ static time_t phar_zip_d2u_time(int dtime, int ddate) /* {{{ */
{ {
struct tm *tm, tmbuf; struct tm *tm, tmbuf;
time_t now; time_t now;
now = time(NULL); now = time(NULL);
tm = php_localtime_r(&now, &tmbuf); tm = php_localtime_r(&now, &tmbuf);
tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
tm->tm_mon = ((ddate>>5)&15) - 1;
tm->tm_mday = ddate&31;
tm->tm_hour = (dtime>>11)&31; tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
tm->tm_min = (dtime>>5)&63; tm->tm_mon = ((ddate>>5)&15) - 1;
tm->tm_sec = (dtime<<1)&62; tm->tm_mday = ddate&31;
return mktime(tm); tm->tm_hour = (dtime>>11)&31;
tm->tm_min = (dtime>>5)&63;
tm->tm_sec = (dtime<<1)&62;
return mktime(tm);
} }
/* }}} */ /* }}} */
static void phar_zip_u2d_time(time_t time, php_uint16 *dtime, php_uint16 *ddate) /* {{{ */ static void phar_zip_u2d_time(time_t time, php_uint16 *dtime, php_uint16 *ddate) /* {{{ */
{ {
struct tm *tm, tmbuf; struct tm *tm, tmbuf;
tm = php_localtime_r(&time, &tmbuf); tm = php_localtime_r(&time, &tmbuf);
*ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday; *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday;
*dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1); *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1);
} }
/* }}} */ /* }}} */
/** /**
* Does not check for a previously opened phar in the cache. * Does not check for a previously opened phar in the cache.
* *
* Parse a new one and add it to the cache, returning either SUCCESS or * Parse a new one and add it to the cache, returning either SUCCESS or
* FAILURE, and setting pphar to the pointer to the manifest entry * FAILURE, and setting pphar to the pointer to the manifest entry
* *
* This is used by phar_open_from_fp to process a zip-based phar, but can be called * This is used by phar_open_from_fp to process a zip-based phar, but can be called
@ -158,6 +166,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
char *p = buf, *ext, *actual_alias = NULL; char *p = buf, *ext, *actual_alias = NULL;
size = php_stream_tell(fp); size = php_stream_tell(fp);
if (size > sizeof(locator) + 65536) { if (size > sizeof(locator) + 65536) {
/* seek to max comment length + end of central directory record */ /* seek to max comment length + end of central directory record */
size = sizeof(locator) + 65536; size = sizeof(locator) + 65536;
@ -171,6 +180,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
} else { } else {
php_stream_seek(fp, 0, SEEK_SET); php_stream_seek(fp, 0, SEEK_SET);
} }
if (!(read = php_stream_read(fp, buf, size))) { if (!(read = php_stream_read(fp, buf, size))) {
php_stream_close(fp); php_stream_close(fp);
if (error) { if (error) {
@ -178,6 +188,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
} }
return FAILURE; return FAILURE;
} }
while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) { while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
if (!memcmp(p + 1, "K\5\6", 3)) { if (!memcmp(p + 1, "K\5\6", 3)) {
memcpy((void *)&locator, (void *) p, sizeof(locator)); memcpy((void *)&locator, (void *) p, sizeof(locator));
@ -189,6 +200,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
} }
return FAILURE; return FAILURE;
} }
if (locator.counthere != locator.count) { if (locator.counthere != locator.count) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname); spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
@ -196,6 +208,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
php_stream_close(fp); php_stream_close(fp);
return FAILURE; return FAILURE;
} }
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist)); mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist); mydata->is_persistent = PHAR_G(persist);
@ -204,6 +217,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
char *metadata; char *metadata;
metadata = p + sizeof(locator); metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) { if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) { if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname); spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
@ -212,7 +226,9 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
pefree(mydata, mydata->is_persistent); pefree(mydata, mydata->is_persistent);
return FAILURE; return FAILURE;
} }
mydata->metadata_len = PHAR_GET_16(locator.comment_len); mydata->metadata_len = PHAR_GET_16(locator.comment_len);
if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) { if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) {
mydata->metadata_len = 0; mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */ /* if not valid serialized data, it is a regular string */
@ -230,13 +246,17 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
} else { } else {
mydata->metadata = NULL; mydata->metadata = NULL;
} }
goto foundit; goto foundit;
} }
} }
php_stream_close(fp); php_stream_close(fp);
if (error) { if (error) {
spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname); spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
} }
return FAILURE; return FAILURE;
foundit: foundit:
mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent); mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
@ -246,6 +266,7 @@ foundit:
mydata->is_zip = 1; mydata->is_zip = 1;
mydata->fname_len = fname_len; mydata->fname_len = fname_len;
ext = strrchr(mydata->fname, '/'); ext = strrchr(mydata->fname, '/');
if (ext) { if (ext) {
mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext); mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
if (mydata->ext == ext) { if (mydata->ext == ext) {
@ -255,6 +276,7 @@ foundit:
mydata->ext_len = (mydata->fname + fname_len) - mydata->ext; mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
} }
} }
/* clean up on big-endian systems */ /* clean up on big-endian systems */
/* seek to central directory */ /* seek to central directory */
php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET); php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
@ -297,12 +319,17 @@ foundit:
if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) { if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
PHAR_ZIP_FAIL("unable to read central directory entry, truncated"); PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
} }
/* clean up for bigendian systems */ /* clean up for bigendian systems */
if (memcmp("PK\1\2", zipentry.signature, 4)) { if (memcmp("PK\1\2", zipentry.signature, 4)) {
/* corrupted entry */ /* corrupted entry */
PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature"); PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
} }
if (entry.is_persistent) entry.manifest_pos = i;
if (entry.is_persistent) {
entry.manifest_pos = i;
}
entry.compressed_filesize = PHAR_GET_32(zipentry.compsize); entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize); entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
entry.crc32 = PHAR_GET_32(zipentry.crc32); entry.crc32 = PHAR_GET_32(zipentry.crc32);
@ -312,19 +339,25 @@ foundit:
entry.header_offset = PHAR_GET_32(zipentry.offset); entry.header_offset = PHAR_GET_32(zipentry.offset);
entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) + entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) +
PHAR_GET_16(zipentry.extra_len); PHAR_GET_16(zipentry.extra_len);
if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) { if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
PHAR_ZIP_FAIL("Cannot process encrypted zip files"); PHAR_ZIP_FAIL("Cannot process encrypted zip files");
} }
if (!PHAR_GET_16(zipentry.filename_len)) { if (!PHAR_GET_16(zipentry.filename_len)) {
PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)"); PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
} }
entry.filename_len = PHAR_GET_16(zipentry.filename_len); entry.filename_len = PHAR_GET_16(zipentry.filename_len);
entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent); entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent);
if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) { if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated"); PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
} }
entry.filename[entry.filename_len] = '\0'; entry.filename[entry.filename_len] = '\0';
if (entry.filename[entry.filename_len - 1] == '/') { if (entry.filename[entry.filename_len - 1] == '/') {
entry.is_dir = 1; entry.is_dir = 1;
entry.filename_len--; entry.filename_len--;
@ -332,7 +365,9 @@ foundit:
} else { } else {
entry.is_dir = 0; entry.is_dir = 0;
} }
phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len TSRMLS_CC); phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len TSRMLS_CC);
if (PHAR_GET_16(zipentry.extra_len)) { if (PHAR_GET_16(zipentry.extra_len)) {
off_t loc = php_stream_tell(fp); off_t loc = php_stream_tell(fp);
if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) { if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) {
@ -341,6 +376,7 @@ foundit:
} }
php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET); php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
} }
switch (zipentry.compressed) { switch (zipentry.compressed) {
case PHAR_ZIP_COMP_NONE : case PHAR_ZIP_COMP_NONE :
/* compression flag already set */ /* compression flag already set */
@ -399,14 +435,17 @@ foundit:
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip"); PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
} }
/* get file metadata */ /* get file metadata */
if (zipentry.comment_len) { if (zipentry.comment_len) {
if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) { if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in file comment, truncated"); PHAR_ZIP_FAIL("unable to read in file comment, truncated");
} }
p = buf; p = buf;
entry.metadata_len = zipentry.comment_len; entry.metadata_len = zipentry.comment_len;
if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) { if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) {
entry.metadata_len = 0; entry.metadata_len = 0;
/* if not valid serialized data, it is a regular string */ /* if not valid serialized data, it is a regular string */
@ -423,41 +462,51 @@ foundit:
} else { } else {
entry.metadata = NULL; entry.metadata = NULL;
} }
if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
php_stream_filter *filter; php_stream_filter *filter;
off_t saveloc; off_t saveloc;
/* archive alias found, seek to file contents, do not validate local header. Potentially risky, but /* archive alias found, seek to file contents, do not validate local header. Potentially risky, but not very. */
not very. */
saveloc = php_stream_tell(fp); saveloc = php_stream_tell(fp);
php_stream_seek(fp, PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET); php_stream_seek(fp, PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
mydata->alias_len = entry.uncompressed_filesize; mydata->alias_len = entry.uncompressed_filesize;
if (entry.flags & PHAR_ENT_COMPRESSED_GZ) { if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC); filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
if (!filter) { if (!filter) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed"); PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
} }
php_stream_filter_append(&fp->readfilters, filter); php_stream_filter_append(&fp->readfilters, filter);
if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, truncated"); PHAR_ZIP_FAIL("unable to read in alias, truncated");
} }
php_stream_filter_flush(filter, 1); php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC); php_stream_filter_remove(filter, 1 TSRMLS_CC);
} else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) { } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
php_stream_filter *filter; php_stream_filter *filter;
filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
if (!filter) { if (!filter) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed"); PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
} }
php_stream_filter_append(&fp->readfilters, filter); php_stream_filter_append(&fp->readfilters, filter);
php_stream_filter_append(&fp->readfilters, filter); php_stream_filter_append(&fp->readfilters, filter);
if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
pefree(entry.filename, entry.is_persistent); pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, truncated"); PHAR_ZIP_FAIL("unable to read in alias, truncated");
} }
php_stream_filter_flush(filter, 1); php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC); php_stream_filter_remove(filter, 1 TSRMLS_CC);
} else { } else {
@ -470,16 +519,21 @@ foundit:
/* return to central directory parsing */ /* return to central directory parsing */
php_stream_seek(fp, saveloc, SEEK_SET); php_stream_seek(fp, saveloc, SEEK_SET);
} }
phar_set_inode(&entry TSRMLS_CC); phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL); zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL);
} }
mydata->fp = fp; mydata->fp = fp;
if (zend_hash_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) { if (zend_hash_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
mydata->is_data = 0; mydata->is_data = 0;
} else { } else {
mydata->is_data = 1; mydata->is_data = 1;
} }
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
if (actual_alias) { if (actual_alias) {
phar_archive_data **fd_ptr; phar_archive_data **fd_ptr;
@ -491,7 +545,9 @@ foundit:
zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len); zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
return FAILURE; return FAILURE;
} }
mydata->is_temporary_alias = 0; mydata->is_temporary_alias = 0;
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) { if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) {
if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) { if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
if (error) { if (error) {
@ -502,10 +558,13 @@ foundit:
return FAILURE; return FAILURE;
} }
} }
mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias; mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
if (entry.is_persistent) { if (entry.is_persistent) {
efree(actual_alias); efree(actual_alias);
} }
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
} else { } else {
phar_archive_data **fd_ptr; phar_archive_data **fd_ptr;
@ -520,6 +579,7 @@ foundit:
return FAILURE; return FAILURE;
} }
} }
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent); mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
mydata->alias_len = alias_len; mydata->alias_len = alias_len;
@ -527,12 +587,14 @@ foundit:
mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent); mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
mydata->alias_len = fname_len; mydata->alias_len = fname_len;
} }
mydata->is_temporary_alias = 1; mydata->is_temporary_alias = 1;
} }
if (pphar) { if (pphar) {
*pphar = mydata; *pphar = mydata;
} }
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
@ -570,6 +632,7 @@ int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_l
if (error) { if (error) {
spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname); spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname);
} }
return FAILURE; return FAILURE;
} }
/* }}} */ /* }}} */
@ -595,9 +658,11 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
entry = (phar_entry_info *)data; entry = (phar_entry_info *)data;
p = (struct _phar_zip_pass*) arg; p = (struct _phar_zip_pass*) arg;
if (entry->is_mounted) { if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
if (entry->is_deleted) { if (entry->is_deleted) {
if (entry->fp_refcount <= 0) { if (entry->fp_refcount <= 0) {
return ZEND_HASH_APPLY_REMOVE; return ZEND_HASH_APPLY_REMOVE;
@ -606,6 +671,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
} }
memset(&local, 0, sizeof(local)); memset(&local, 0, sizeof(local));
memset(&central, 0, sizeof(central)); memset(&central, 0, sizeof(central));
memset(&perms, 0, sizeof(perms)); memset(&perms, 0, sizeof(perms));
@ -620,18 +686,22 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
CRC32(perms.crc32, (char)perms.perms & 0xFF); CRC32(perms.crc32, (char)perms.perms & 0xFF);
CRC32(perms.crc32, (char)perms.perms & 0xFF00 >> 8); CRC32(perms.crc32, (char)perms.perms & 0xFF00 >> 8);
perms.crc32 = PHAR_SET_32(~(perms.crc32)); perms.crc32 = PHAR_SET_32(~(perms.crc32));
if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE); local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE);
} }
if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) { if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2); local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2);
} }
/* do not use PHAR_SET_16 on either field of the next line */ /* do not use PHAR_SET_16 on either field of the next line */
phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp); phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp);
central.timestamp = local.timestamp; central.timestamp = local.timestamp;
central.datestamp = local.datestamp; central.datestamp = local.datestamp;
central.filename_len = local.filename_len = PHAR_SET_16(entry->filename_len + (entry->is_dir ? 1 : 0)); central.filename_len = local.filename_len = PHAR_SET_16(entry->filename_len + (entry->is_dir ? 1 : 0));
central.offset = PHAR_SET_32(php_stream_tell(p->filefp)); central.offset = PHAR_SET_32(php_stream_tell(p->filefp));
/* do extra field for perms later */ /* do extra field for perms later */
if (entry->is_modified) { if (entry->is_modified) {
php_uint32 loc; php_uint32 loc;
@ -647,29 +717,36 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
} }
goto continue_dir; goto continue_dir;
} }
if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) { if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
efp = phar_get_efp(entry, 0 TSRMLS_CC);
efp = phar_get_efp(entry, 0 TSRMLS_CC);
newcrc32 = ~0; newcrc32 = ~0;
for (loc = 0;loc < entry->uncompressed_filesize; ++loc) { for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
CRC32(newcrc32, php_stream_getc(efp)); CRC32(newcrc32, php_stream_getc(efp));
} }
entry->crc32 = ~newcrc32; entry->crc32 = ~newcrc32;
central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
/* not compressed */ /* not compressed */
entry->compressed_filesize = entry->uncompressed_filesize; entry->compressed_filesize = entry->uncompressed_filesize;
central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
goto not_compressed; goto not_compressed;
} }
filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC); filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
if (!filter) { if (!filter) {
if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
@ -683,20 +760,26 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
/* work around inability to specify freedom in write and strictness /* work around inability to specify freedom in write and strictness
in read count */ in read count */
entry->cfp = php_stream_fopen_tmpfile(); entry->cfp = php_stream_fopen_tmpfile();
if (!entry->cfp) { if (!entry->cfp) {
spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
php_stream_flush(efp); php_stream_flush(efp);
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
php_stream_filter_append((&entry->cfp->writefilters), filter); php_stream_filter_append((&entry->cfp->writefilters), filter);
if (entry->uncompressed_filesize != php_stream_copy_to_stream(efp, entry->cfp, entry->uncompressed_filesize)) { if (entry->uncompressed_filesize != php_stream_copy_to_stream(efp, entry->cfp, entry->uncompressed_filesize)) {
spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
php_stream_filter_flush(filter, 1); php_stream_filter_flush(filter, 1);
php_stream_flush(entry->cfp); php_stream_flush(entry->cfp);
php_stream_filter_remove(filter, 1 TSRMLS_CC); php_stream_filter_remove(filter, 1 TSRMLS_CC);
@ -710,6 +793,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
} else { } else {
central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) { if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
@ -732,29 +816,36 @@ continue_dir:
PHP_VAR_SERIALIZE_DESTROY(metadata_hash); PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
central.comment_len = PHAR_SET_16(entry->metadata_str.len); central.comment_len = PHAR_SET_16(entry->metadata_str.len);
} }
entry->header_offset = php_stream_tell(p->filefp); entry->header_offset = php_stream_tell(p->filefp);
offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms); offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) { if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) { if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) {
spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (entry->is_dir) { if (entry->is_dir) {
if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) { if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (1 != php_stream_write(p->filefp, "/", 1)) { if (1 != php_stream_write(p->filefp, "/", 1)) {
spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) { if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (1 != php_stream_write(p->centralfp, "/", 1)) { if (1 != php_stream_write(p->centralfp, "/", 1)) {
spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
@ -764,40 +855,49 @@ continue_dir:
spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) { if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
} }
if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) { if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) { if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
if (entry->is_modified) { if (entry->is_modified) {
if (entry->cfp) { if (entry->cfp) {
if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) { if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) {
spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
php_stream_close(entry->cfp); php_stream_close(entry->cfp);
entry->cfp = NULL; entry->cfp = NULL;
} else { } else {
if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) { if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC); phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC);
if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) { if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) {
spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
} }
if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) { if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
php_stream_close(entry->fp); php_stream_close(entry->fp);
} }
entry->is_modified = 0; entry->is_modified = 0;
} else { } else {
if (entry->fp_refcount) { if (entry->fp_refcount) {
@ -812,22 +912,27 @@ continue_dir:
break; break;
} }
} }
if (!entry->is_dir && entry->compressed_filesize && entry->compressed_filesize != php_stream_copy_to_stream(p->old, p->filefp, entry->compressed_filesize)) { if (!entry->is_dir && entry->compressed_filesize && entry->compressed_filesize != php_stream_copy_to_stream(p->old, p->filefp, entry->compressed_filesize)) {
spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
} }
entry->fp = NULL; entry->fp = NULL;
entry->offset = entry->offset_abs = offset; entry->offset = entry->offset_abs = offset;
entry->fp_type = PHAR_FP; entry->fp_type = PHAR_FP;
if (entry->metadata_str.c) { if (entry->metadata_str.c) {
if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) { if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) {
spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
smart_str_free(&entry->metadata_str); smart_str_free(&entry->metadata_str);
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} }
smart_str_free(&entry->metadata_str); smart_str_free(&entry->metadata_str);
} }
return ZEND_HASH_APPLY_KEEP; return ZEND_HASH_APPLY_KEEP;
} }
/* }}} */ /* }}} */
@ -859,6 +964,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
if (phar->is_data) { if (phar->is_data) {
goto nostub; goto nostub;
} }
@ -866,15 +972,18 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
/* set alias */ /* set alias */
if (!phar->is_temporary_alias && phar->alias_len) { if (!phar->is_temporary_alias && phar->alias_len) {
entry.fp = php_stream_fopen_tmpfile(); entry.fp = php_stream_fopen_tmpfile();
if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) { if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
if (error) { if (error) {
spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
} }
return EOF; return EOF;
} }
entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len; entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len;
entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1); entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
entry.filename_len = sizeof(".phar/alias.txt")-1; entry.filename_len = sizeof(".phar/alias.txt")-1;
if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
if (error) { if (error) {
spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
@ -884,6 +993,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else { } else {
zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1); zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
} }
/* register alias */ /* register alias */
if (phar->alias_len) { if (phar->alias_len) {
if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) { if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) {
@ -901,12 +1011,15 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
if (len == -1) { if (len == -1) {
len = PHP_STREAM_COPY_ALL; len = PHP_STREAM_COPY_ALL;
} else { } else {
len = -len; len = -len;
} }
user_stub = 0; user_stub = 0;
if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) { if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
if (error) { if (error) {
spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname); spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
@ -917,6 +1030,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else { } else {
free_user_stub = 0; free_user_stub = 0;
} }
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{ {
if (error) { if (error) {
@ -927,6 +1041,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
len = pos - user_stub + 18; len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile(); entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5; entry.uncompressed_filesize = len + 5;
@ -942,8 +1057,10 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
php_stream_close(entry.fp); php_stream_close(entry.fp);
return EOF; return EOF;
} }
entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
entry.filename_len = sizeof(".phar/stub.php")-1; entry.filename_len = sizeof(".phar/stub.php")-1;
if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
if (free_user_stub) { if (free_user_stub) {
efree(user_stub); efree(user_stub);
@ -953,6 +1070,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
return EOF; return EOF;
} }
if (free_user_stub) { if (free_user_stub) {
efree(user_stub); efree(user_stub);
} }
@ -997,9 +1115,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} }
} }
} }
nostub: nostub:
if (phar->fp && !phar->is_brandnew) { if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp; oldfile = phar->fp;
closeoldfile = 0; closeoldfile = 0;
@ -1012,6 +1128,7 @@ nostub:
/* save modified files to the zip */ /* save modified files to the zip */
pass.old = oldfile; pass.old = oldfile;
pass.filefp = php_stream_fopen_tmpfile(); pass.filefp = php_stream_fopen_tmpfile();
if (!pass.filefp) { if (!pass.filefp) {
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
@ -1021,7 +1138,9 @@ nostub:
} }
return EOF; return EOF;
} }
pass.centralfp = php_stream_fopen_tmpfile(); pass.centralfp = php_stream_fopen_tmpfile();
if (!pass.centralfp) { if (!pass.centralfp) {
if (closeoldfile) { if (closeoldfile) {
php_stream_close(oldfile); php_stream_close(oldfile);
@ -1031,12 +1150,14 @@ nostub:
} }
return EOF; return EOF;
} }
pass.free_fp = pass.free_ufp = 1; pass.free_fp = pass.free_ufp = 1;
memset(&eocd, 0, sizeof(eocd)); memset(&eocd, 0, sizeof(eocd));
strncpy(eocd.signature, "PK\5\6", 4); strncpy(eocd.signature, "PK\5\6", 4);
eocd.counthere = eocd.count = zend_hash_num_elements(&phar->manifest); eocd.counthere = eocd.count = zend_hash_num_elements(&phar->manifest);
zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC); zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC);
if (temperr) { if (temperr) {
php_stream_close(pass.filefp); php_stream_close(pass.filefp);
php_stream_close(pass.centralfp); php_stream_close(pass.centralfp);
@ -1054,6 +1175,7 @@ nostub:
eocd.cdir_size = php_stream_tell(pass.centralfp); eocd.cdir_size = php_stream_tell(pass.centralfp);
eocd.cdir_offset = php_stream_tell(pass.filefp); eocd.cdir_offset = php_stream_tell(pass.filefp);
php_stream_seek(pass.centralfp, 0, SEEK_SET); php_stream_seek(pass.centralfp, 0, SEEK_SET);
if (eocd.cdir_size != php_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL)) { if (eocd.cdir_size != php_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL)) {
php_stream_close(pass.filefp); php_stream_close(pass.filefp);
php_stream_close(pass.centralfp); php_stream_close(pass.centralfp);
@ -1065,13 +1187,16 @@ nostub:
} }
return EOF; return EOF;
} }
php_stream_close(pass.centralfp); php_stream_close(pass.centralfp);
if (phar->metadata) { if (phar->metadata) {
/* set phar metadata */ /* set phar metadata */
PHP_VAR_SERIALIZE_INIT(metadata_hash); PHP_VAR_SERIALIZE_INIT(metadata_hash);
php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC); php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(metadata_hash); PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
eocd.comment_len = PHAR_SET_16(main_metadata_str.len); eocd.comment_len = PHAR_SET_16(main_metadata_str.len);
if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
php_stream_close(pass.filefp); php_stream_close(pass.filefp);
if (error) { if (error) {
@ -1083,6 +1208,7 @@ nostub:
smart_str_free(&main_metadata_str); smart_str_free(&main_metadata_str);
return EOF; return EOF;
} }
if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) { if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) {
php_stream_close(pass.filefp); php_stream_close(pass.filefp);
if (error) { if (error) {
@ -1094,7 +1220,9 @@ nostub:
smart_str_free(&main_metadata_str); smart_str_free(&main_metadata_str);
return EOF; return EOF;
} }
smart_str_free(&main_metadata_str); smart_str_free(&main_metadata_str);
} else { } else {
if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
php_stream_close(pass.filefp); php_stream_close(pass.filefp);
@ -1107,17 +1235,21 @@ nostub:
return EOF; return EOF;
} }
} }
if (phar->fp && pass.free_fp) { if (phar->fp && pass.free_fp) {
php_stream_close(phar->fp); php_stream_close(phar->fp);
} }
if (phar->ufp) { if (phar->ufp) {
if (pass.free_ufp) { if (pass.free_ufp) {
php_stream_close(phar->ufp); php_stream_close(phar->ufp);
} }
phar->ufp = NULL; phar->ufp = NULL;
} }
/* re-open */ /* re-open */
phar->is_brandnew = 0; phar->is_brandnew = 0;
if (phar->donotflush) { if (phar->donotflush) {
/* deferred flush */ /* deferred flush */
phar->fp = pass.filefp; phar->fp = pass.filefp;