1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

- This is as good as it gets in HEAD at present (~30% tests fail here)

This commit is contained in:
Steph Fox
2008-08-01 13:45:06 +00:00
parent 63249f7ea3
commit c6aa379d74
23 changed files with 4449 additions and 1522 deletions

View File

@@ -4,22 +4,42 @@ $(srcdir)/phar_path_check.c: $(srcdir)/phar_path_check.re
pharcmd: $(builddir)/phar.php $(builddir)/phar.phar
PHP_PHARCMD_SETTINGS = -d 'open_basedir=' -d 'output_buffering=0' -d 'memory_limit=-1' -d phar.readonly=0
PHP_PHARCMD_EXECUTABLE = ` \
if test -x "$(top_builddir)/$(SAPI_CLI_PATH)"; then \
$(top_srcdir)/build/shtool echo -n -- "$(top_builddir)/$(SAPI_CLI_PATH) -n"; \
if test "x$(PHP_MODULES)" != "x"; then \
$(top_srcdir)/build/shtool echo -n -- " -d extension_dir=$(top_builddir)/modules"; \
for i in bz2 zlib phar; do \
if test -f "$(top_builddir)/modules/$$i.la"; then \
. $(top_builddir)/modules/$$i.la; $(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \
fi; \
done; \
fi; \
else \
$(top_srcdir)/build/shtool echo -n -- "$(PHP_EXECUTABLE)"; \
fi;`
PHP_PHARCMD_BANG = `if test -x "$(PHP_EXECUTABLE)"; then \
$(top_srcdir)/build/shtool echo -n -- "$(PHP_EXECUTABLE)"; \
else \
$(top_srcdir)/build/shtool echo -n -- "$(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT)"; \
fi; `
$(builddir)/phar/phar.inc: $(srcdir)/phar/phar.inc
-@test -d $(builddir)/phar || mkdir $(builddir)/phar
-@test -f $(builddir)/phar/phar.inc || cp $(srcdir)/phar/phar.inc $(builddir)/phar/phar.inc
$(builddir)/phar.php: $(srcdir)/build_precommand.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH)
if test -x "$(PHP_EXECUTABLE)"; then \
export PHP="$(PHP_EXECUTABLE)"; \
else \
export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \
fi; \
$$PHP $(srcdir)/build_precommand.php > $(builddir)/phar.php
-@echo "Generating phar.php"
@$(PHP_PHARCMD_EXECUTABLE) $(PHP_PHARCMD_SETTINGS) $(srcdir)/build_precommand.php > $(builddir)/phar.php
$(builddir)/phar.phar: $(builddir)/phar.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH)
if test -x "$(PHP_EXECUTABLE)"; then \
export PHP="$(PHP_EXECUTABLE)"; \
export BANG="$(PHP_EXECUTABLE)"; \
else \
export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \
export BANG="$(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT)"; \
fi; \
$$PHP -d phar.readonly=0 $(srcdir)/phar.php pack -f $(builddir)/phar.phar -a pharcommand -c auto -x CVS -p 0 -s $(srcdir)/phar/phar.php -h sha1 -b "$$BANG" $(srcdir)/phar/
@chmod +x $(builddir)/phar.phar
$(builddir)/phar.phar: $(builddir)/phar.php $(builddir)/phar/phar.inc $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH)
-@echo "Generating phar.phar"
-@rm -f $(builddir)/phar.phar
-@rm -f $(srcdir)/phar.phar
@$(PHP_PHARCMD_EXECUTABLE) $(PHP_PHARCMD_SETTINGS) $(builddir)/phar.php pack -f $(builddir)/phar.phar -a pharcommand -c auto -x CVS -p 0 -s $(srcdir)/phar/phar.php -h sha1 -b "$(PHP_PHARCMD_BANG)" $(srcdir)/phar/
-@chmod +x $(builddir)/phar.phar
install-pharcmd: pharcmd
-@$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
$(INSTALL) $(builddir)/phar.phar $(INSTALL_ROOT)$(bindir)

View File

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

View File

@@ -1,11 +1,11 @@
#!/bin/sh
export SCRIPT_NAME=/front.phar.php
export PATH_INFO=
export PATH_INFO=/index.php
export SCRIPT_FILENAME=/home/cellog/workspace/php5/ext/phar/tests/front.phar.php
export PATH_TRANSLATED=/home/cellog/workspace/php5/ext/phar/tests/front.phar.php
export REDIRECT_STATUS=1
export REQUEST_METHOD=GET
export REQUEST_URI=/front.phar.php
cd /home/cellog/workspace/php5/
export REQUEST_URI=/front.phar.php/index.php
cd /home/cellog/workspace/php5
ddd sapi/cgi/php-cgi &
cd /home/cellog/workspace/php5/ext/phar

View File

@@ -2,12 +2,23 @@ dnl $Id$
dnl config.m4 for extension phar
PHP_ARG_ENABLE(phar, for phar archive support,
[ --enable-phar Enable phar support])
[ --enable-phar Enable phar support])
if test "$PHP_PHAR" != "no"; then
PHP_NEW_EXTENSION(phar, util.c tar.c zip.c stream.c func_interceptors.c dirstream.c phar.c phar_object.c phar_path_check.c, $ext_shared)
PHP_ADD_BUILD_DIR($ext_builddir/lib, 1)
PHP_SUBST(PHAR_SHARED_LIBADD)
AC_MSG_CHECKING([for phar openssl support])
if test "$PHP_OPENSSL_SHARED" = "yes"; then
AC_MSG_RESULT([no (shared openssl)])
else
if test "$PHP_OPENSSL" = "yes"; then
AC_MSG_RESULT([yes])
AC_DEFINE(PHAR_HAVE_OPENSSL,1,[ ])
else
AC_MSG_RESULT([no])
fi
fi
PHP_ADD_EXTENSION_DEP(phar, spl, true)
PHP_ADD_MAKEFILE_FRAGMENT
fi

View File

@@ -2,11 +2,37 @@
// vim:ft=javascript
ARG_ENABLE("phar", "enable phar support", "no");
ARG_ENABLE("phar-native-ssl", "enable phar with native OpenSSL support", "no");
if (PHP_PHAR_NATIVE_SSL != "no") {
PHP_PHAR = PHP_PHAR_NATIVE_SSL;
PHP_PHAR_SHARED = PHP_PHAR_NATIVE_SSL_SHARED;
}
if (PHP_PHAR != "no") {
EXTENSION("phar", "dirstream.c func_interceptors.c phar.c phar_object.c phar_path_check.c stream.c tar.c util.c zip.c");
if (PHP_PHAR_SHARED) {
ADD_FLAG("CFLAGS_PHAR", "/D COMPILE_DL_PHAR ");
}
if (PHP_PHAR_NATIVE_SSL != "no") {
if (CHECK_LIB("libeay32st.lib", "phar")) {
/* We don't really need GDI for this, but there's no
way to avoid linking it in the static openssl build */
ADD_FLAG("LIBS_PHAR", "libeay32st.lib gdi32.lib");
if (PHP_DEBUG == "no") {
/* Silence irrelevant-to-us warning in release builds */
ADD_FLAG("LDFLAGS_PHAR", "/IGNORE:4089 ");
}
AC_DEFINE('PHAR_HAVE_OPENSSL', 1);
STDOUT.WriteLine(' Native OpenSSL support in Phar enabled');
} else {
WARNING('Could not enable native OpenSSL support in Phar');
}
} else {
/* If ext/openssl is built-in we can at least use the API directly */
if (PHP_OPENSSL != "no" && !PHP_OPENSSL_SHARED) {
AC_DEFINE('PHAR_HAVE_OPENSSL', 1);
}
}
ADD_EXTENSION_DEP('phar', 'spl', true);
}

View File

@@ -45,13 +45,13 @@ static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{
{
HashTable *data = (HashTable *)stream->abstract;
if (data && data->arBuckets)
{
if (data && data->arBuckets) {
zend_hash_destroy(data);
data->arBuckets = 0;
FREE_HASHTABLE(data);
stream->abstract = NULL;
}
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;
if (!data)
{
if (!data) {
return -1;
}
if (whence == SEEK_END) {
whence = SEEK_SET;
offset = zend_hash_num_elements(data) + offset;
}
if (whence == SEEK_SET) {
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)) {
return 0;
}
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) {
return 0;
}
PHAR_STR(key, str_key);
zend_hash_move_forward(data);
to_read = MIN(keylen, count);
if (to_read == 0 || count < keylen) {
return 0;
}
memset(buf, 0, sizeof(php_stream_dirent));
memcpy(((php_stream_dirent *) buf)->d_name, str_key, to_read);
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
@@ -145,9 +150,9 @@ static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */
*/
static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */
{
void *dummy = (void *) 1;
void *dummy = (char *) 1;
return zend_hash_update(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
return zend_hash_update(ht, arKey, nKeyLength, (void *) &dummy, sizeof(void *), NULL);
}
/* }}} */
@@ -159,10 +164,9 @@ static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC) /* {{{
Bucket *f;
Bucket *s;
int result;
f = *((Bucket **) a);
s = *((Bucket **) b);
#if (PHP_MAJOR_VERSION < 6)
result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
#else
@@ -202,12 +206,16 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
efree(dir);
return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
}
zend_hash_internal_pointer_reset(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)) {
break;
}
PHAR_STR(key, str_key);
if (keylen <= (uint)dirlen) {
if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
if (SUCCESS != zend_hash_move_forward(manifest)) {
@@ -216,6 +224,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC)
continue;
}
}
if (*dir == '/') {
/* root directory */
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;
}
if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
/* the entry has a path separator and is a subdirectory */
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);
entry[keylen] = '\0';
}
goto PHAR_ADD_ENTRY;
} else {
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 += dirlen + 1; /* seek to just past the path separator */
if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
/* is subdirectory */
save -= dirlen + 1;
@@ -274,11 +287,14 @@ PHAR_ADD_ENTRY:
if (keylen) {
phar_add_empty(data, entry, keylen);
}
efree(entry);
if (SUCCESS != zend_hash_move_forward(manifest)) {
break;
}
}
if (FAILURE != zend_hash_has_more_elements(data)) {
efree(dir);
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
*/
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) /* {{{ */
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) /* {{{ */
{
php_url *resource = NULL;
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);
phar_request_initialize(TSRMLS_C);
internal_file = resource->path + 1; /* strip leading "/" */
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
if (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);
return NULL;
}
if (error) {
efree(error);
}
if (*internal_file == '\0') {
/* root directory requested */
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);
return ret;
}
if (!phar->manifest.arBuckets) {
php_url_free(resource);
return NULL;
}
if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) {
php_url_free(resource);
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);
}
}
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
break;
}
@@ -415,43 +435,45 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
/* pre-readonly check, we need to know if this is a data phar */
if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
return FAILURE;
return 0;
}
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL;
}
efree(arch);
efree(entry2);
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);
return FAILURE;
return 0;
}
if ((resource = phar_parse_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) {
return FAILURE;
return 0;
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if (!resource->scheme || !resource->host || !resource->path) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from);
return FAILURE;
return 0;
}
if (strcasecmp("phar", resource->scheme)) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from);
return FAILURE;
return 0;
}
host_len = strlen(resource->host);
phar_request_initialize(TSRMLS_C);
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
return FAILURE;
return 0;
}
if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1 TSRMLS_CC))) {
@@ -462,25 +484,34 @@ 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\" in phar \"%s\", directory already exists", resource->path+1, resource->host);
php_url_free(resource);
return FAILURE;
return 0;
}
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);
efree(error);
php_url_free(resource);
return FAILURE;
return 0;
}
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 */
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);
return FAILURE;
return 0;
}
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);
efree(error);
php_url_free(resource);
return FAILURE;
return 0;
}
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
php_url_free(resource);
return 0;
}
memset((void *) &entry, 0, sizeof(phar_entry_info));
@@ -489,11 +520,14 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
if (phar->is_zip) {
entry.is_zip = 1;
}
entry.filename = estrdup(resource->path + 1);
if (phar->is_tar) {
entry.is_tar = 1;
entry.tar_type = TAR_DIR;
}
entry.filename_len = strlen(resource->path + 1);
php_url_free(resource);
entry.is_dir = 1;
@@ -502,20 +536,25 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
entry.is_crc_checked = 1;
entry.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)) {
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(entry.filename);
return FAILURE;
return 0;
}
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
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);
zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
efree(error);
return FAILURE;
return 0;
}
return SUCCESS;
phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC);
return 1;
}
/* }}} */
@@ -530,50 +569,60 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
int arch_len, entry_len;
php_url *resource = NULL;
uint host_len;
int key_type;
phar_zstr key;
char *str_key;
uint key_len;
ulong unused;
uint path_len;
/* pre-readonly check, we need to know if this is a data phar */
if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
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 FAILURE;
return 0;
}
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL;
}
efree(arch);
efree(entry2);
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);
return FAILURE;
return 0;
}
if ((resource = phar_parse_url(wrapper, url, "w", options TSRMLS_CC)) == NULL) {
return FAILURE;
return 0;
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if (!resource->scheme || !resource->host || !resource->path) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
return FAILURE;
return 0;
}
if (strcasecmp("phar", resource->scheme)) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
return FAILURE;
return 0;
}
host_len = strlen(resource->host);
phar_request_initialize(TSRMLS_C);
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
return FAILURE;
return 0;
}
if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error, 1 TSRMLS_CC))) {
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 (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);
efree(error);
@@ -581,21 +630,83 @@ 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\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
}
php_url_free(resource);
return FAILURE;
return 0;
}
/* now for the easy part */
entry->is_deleted = 1;
entry->is_modified = 1;
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
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);
zend_hash_del(&phar->manifest, entry->filename, entry->filename_len);
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
php_url_free(resource);
efree(error);
return FAILURE;
return 0;
}
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));
zend_hash_move_forward(&phar->manifest)) {
PHAR_STR(key, str_key);
if (!entry->is_deleted &&
key_len > path_len &&
memcmp(str_key, resource->path+1, path_len) == 0 &&
IS_SLASH(str_key[path_len])) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
if (entry->is_temp_dir) {
efree(entry->filename);
efree(entry);
}
php_url_free(resource);
return 0;
}
}
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));
zend_hash_move_forward(&phar->virtual_dirs)) {
PHAR_STR(key, str_key);
if (!entry->is_deleted &&
key_len > path_len &&
memcmp(str_key, resource->path+1, path_len) == 0 &&
IS_SLASH(str_key[path_len])) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
if (entry->is_temp_dir) {
efree(entry->filename);
efree(entry);
}
php_url_free(resource);
return 0;
}
}
if (entry->is_temp_dir) {
zend_hash_del(&phar->virtual_dirs, resource->path+1, path_len);
efree(entry->filename);
efree(entry);
} else {
entry->is_deleted = 1;
entry->is_modified = 1;
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
php_url_free(resource);
efree(error);
return 0;
}
}
php_url_free(resource);
return SUCCESS;
return 1;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| 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, |
| that is bundled with this package in the file LICENSE, and is |

View File

@@ -29,9 +29,15 @@ PHAR_FUNC(phar_opendir) /* {{{ */
int filename_len;
zval *zcontext = NULL;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
return;
}
@@ -97,13 +103,20 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
long maxlen = PHP_STREAM_COPY_ALL;
zval *zcontext = NULL;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
goto skip_phar;
}
/* 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) {
return;
goto skip_phar;
}
if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
char *arch, *entry, *fname;
int arch_len, entry_len, fname_len;
@@ -117,7 +130,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
char *name;
phar_archive_data **pphar;
phar_archive_data *phar;
efree(entry);
entry = filename;
@@ -131,7 +144,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
}
/* retrieving a file defaults to within the current directory, so use this if possible */
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
efree(arch);
goto skip_phar;
}
@@ -147,7 +160,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
} else {
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
/* this file is not in the phar, use the original path */
notfound:
efree(arch);
@@ -155,7 +168,7 @@ notfound:
goto skip_phar;
}
} else {
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
goto notfound;
}
}
@@ -222,7 +235,12 @@ PHAR_FUNC(phar_readfile) /* {{{ */
zval *zcontext = NULL;
php_stream *stream;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) {
@@ -233,7 +251,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
int arch_len, entry_len, fname_len;
php_stream_context *context = NULL;
char *name;
phar_archive_data **pphar;
phar_archive_data *phar;
fname = zend_get_executed_filename(TSRMLS_C);
if (strncasecmp(fname, "phar://", 7)) {
@@ -249,7 +267,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file defaults to within the current directory, so use this if possible */
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
efree(arch);
goto skip_phar;
}
@@ -264,7 +282,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
} else {
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
/* this file is not in the phar, use the original path */
notfound:
efree(entry);
@@ -272,7 +290,7 @@ notfound:
goto skip_phar;
}
} else {
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
goto notfound;
}
}
@@ -312,7 +330,12 @@ PHAR_FUNC(phar_fopen) /* {{{ */
zval *zcontext = NULL;
php_stream *stream;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
/* no need to check, include_path not even specified in fopen/ no active phars */
goto skip_phar;
}
@@ -324,7 +347,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
int arch_len, entry_len, fname_len;
php_stream_context *context = NULL;
char *name;
phar_archive_data **pphar;
phar_archive_data *phar;
fname = zend_get_executed_filename(TSRMLS_C);
if (strncasecmp(fname, "phar://", 7)) {
@@ -340,7 +363,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file defaults to within the current directory, so use this if possible */
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
efree(arch);
goto skip_phar;
}
@@ -355,7 +378,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
} else {
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
/* this file is not in the phar, use the original path */
notfound:
efree(entry);
@@ -363,7 +386,7 @@ notfound:
goto skip_phar;
}
} else {
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
/* this file is not in the phar, use the original path */
goto notfound;
}
@@ -595,8 +618,7 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
int arch_len, entry_len, fname_len;
struct stat sb = {0};
phar_entry_info *data = NULL;
char *tmp;
int tmp_len;
phar_archive_data *phar;
fname = zend_get_executed_filename(TSRMLS_C);
@@ -607,28 +629,57 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
goto skip_phar;
}
fname_len = strlen(fname);
if (PHAR_G(last_phar) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
arch_len = PHAR_G(last_phar_name_len);
entry = estrndup(filename, filename_length);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = (int) filename_length;
phar = PHAR_G(last_phar);
goto splitted;
}
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
efree(entry);
entry = estrndup(filename, filename_length);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = (int) filename_length;
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
efree(arch);
goto skip_phar;
}
splitted:
entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
efree(entry);
goto stat_entry;
}
goto notfound;
}
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &data)) {
efree(entry);
goto stat_entry;
}
if (zend_hash_exists(&(phar->virtual_dirs), entry, entry_len)) {
efree(entry);
efree(arch);
if (IS_EXISTS_CHECK(type)) {
RETURN_TRUE;
}
sb.st_size = 0;
sb.st_mode = 0777;
sb.st_mode |= S_IFDIR; /* regular directory */
#ifdef NETWARE
sb.st_mtime.tv_sec = phar->max_timestamp;
sb.st_atime.tv_sec = phar->max_timestamp;
sb.st_ctime.tv_sec = phar->max_timestamp;
#else
sb.st_mtime = phar->max_timestamp;
sb.st_atime = phar->max_timestamp;
sb.st_ctime = phar->max_timestamp;
#endif
goto statme_baby;
} else {
char *save, *save2, *actual;
int save_len, save2_len, actual_len;
@@ -647,54 +698,42 @@ notfound:
PHAR_G(cwd_len) = 0;
/* clean path without cwd */
entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
efree(entry);
efree(save2);
if (IS_EXISTS_CHECK(type)) {
efree(arch);
RETURN_TRUE;
}
goto stat_entry;
} else {
phar_archive_data *phar = *pphar;
phar_zstr key;
char *str_key;
uint keylen;
ulong unused;
}
if (zend_hash_exists(&(phar->virtual_dirs), entry + 1, entry_len - 1)) {
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
/* original not found either, this is possibly a directory relative to cwd */
zend_hash_internal_pointer_reset(&phar->manifest);
while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
if (HASH_KEY_NON_EXISTANT !=
zend_hash_get_current_key_ex(
&phar->manifest, &key, &keylen, &unused, 0, NULL)) {
PHAR_STR(key, str_key);
if (!memcmp(actual, str_key, actual_len)) {
efree(save2);
efree(entry);
/* directory found, all dirs have the same stat */
if (str_key[actual_len] == '/') {
sb.st_size = 0;
sb.st_mode = 0777;
sb.st_mode |= S_IFDIR; /* regular directory */
#ifdef NETWARE
sb.st_mtime.tv_sec = phar->max_timestamp;
sb.st_atime.tv_sec = phar->max_timestamp;
sb.st_ctime.tv_sec = phar->max_timestamp;
#else
sb.st_mtime = phar->max_timestamp;
sb.st_atime = phar->max_timestamp;
sb.st_ctime = phar->max_timestamp;
#endif
goto statme_baby;
}
}
}
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
break;
}
efree(entry);
efree(save2);
efree(arch);
if (IS_EXISTS_CHECK(type)) {
RETURN_TRUE;
}
sb.st_size = 0;
sb.st_mode = 0777;
sb.st_mode |= S_IFDIR; /* regular directory */
#ifdef NETWARE
sb.st_mtime.tv_sec = phar->max_timestamp;
sb.st_atime.tv_sec = phar->max_timestamp;
sb.st_ctime.tv_sec = phar->max_timestamp;
#else
sb.st_mtime = phar->max_timestamp;
sb.st_atime = phar->max_timestamp;
sb.st_ctime = phar->max_timestamp;
#endif
goto statme_baby;
}
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
efree(entry);
efree(save2);
efree(arch);
@@ -705,6 +744,7 @@ notfound:
RETURN_FALSE;
}
stat_entry:
efree(arch);
if (!data->is_dir) {
sb.st_size = data->uncompressed_filesize;
sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
@@ -743,30 +783,18 @@ stat_entry:
}
statme_baby:
efree(arch);
if (!(*pphar)->is_writeable) {
if (!phar->is_writeable) {
sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
}
sb.st_nlink = 1;
sb.st_rdev = -1;
if (data) {
tmp_len = data->filename_len + (*pphar)->alias_len;
} else {
tmp_len = (*pphar)->alias_len + 1;
}
tmp = (char *) emalloc(tmp_len);
memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len);
if (data) {
memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len);
} else {
*(tmp + (*pphar)->alias_len) = '/';
}
/* this is only for APC, so use /dev/null device - no chance of conflict there! */
sb.st_dev = 0xc;
/* generate unique inode number for alias/filename, so no phars will conflict */
sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
efree(tmp);
if (data) {
sb.st_ino = data->inode;
}
#ifndef PHP_WIN32
sb.st_blksize = -1;
sb.st_blocks = -1;
@@ -783,14 +811,18 @@ skip_phar:
#define PharFileFunction(fname, funcnum, orig) \
void fname(INTERNAL_FUNCTION_PARAMETERS) { \
char *filename; \
int filename_len; \
\
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \
return; \
if (!PHAR_G(intercepted)) { \
PHAR_G(orig)(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
} else { \
char *filename; \
int filename_len; \
\
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \
return; \
} \
\
phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
} \
\
phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
}
/* }}} */
@@ -854,13 +886,13 @@ PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable)
PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable)
/* }}} */
/* {{{ proto bool is_executable(string filename)
Returns true if file is executable */
/* {{{ proto bool file_exists(string filename)
Returns true if filename exists */
PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists)
/* }}} */
/* {{{ proto bool is_executable(string filename)
Returns true if file is executable */
/* {{{ proto bool is_dir(string filename)
Returns true if file is directory */
PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir)
/* }}} */
@@ -869,7 +901,12 @@ PHAR_FUNC(phar_is_file) /* {{{ */
char *filename;
int filename_len;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
@@ -888,19 +925,19 @@ PHAR_FUNC(phar_is_file) /* {{{ */
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
phar_archive_data *phar;
efree(entry);
entry = filename;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar_entry_info *etemp;
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
/* this file is not in the current directory, use the original path */
found_it:
efree(entry);
@@ -908,7 +945,7 @@ found_it:
RETURN_BOOL(!etemp->is_dir);
}
} else {
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
goto found_it;
}
}
@@ -929,7 +966,12 @@ PHAR_FUNC(phar_is_link) /* {{{ */
char *filename;
int filename_len;
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (!PHAR_G(intercepted)) {
goto skip_phar;
}
if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
&& !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
@@ -948,19 +990,19 @@ PHAR_FUNC(phar_is_link) /* {{{ */
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
phar_archive_data *phar;
efree(entry);
entry = filename;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar_entry_info *etemp;
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
if (entry[0] == '/') {
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
/* this file is not in the current directory, use the original path */
found_it:
efree(entry);
@@ -968,7 +1010,7 @@ found_it:
RETURN_BOOL(etemp->link);
}
} else {
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
goto found_it;
}
}
@@ -979,7 +1021,7 @@ found_it:
}
}
skip_phar:
PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
PHAR_G(orig_is_link)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
return;
}
/* }}} */
@@ -995,6 +1037,24 @@ PharFileFunction(phar_stat, FS_STAT, orig_stat)
/* }}} */
/* {{{ void phar_intercept_functions(TSRMLS_D) */
void phar_intercept_functions(TSRMLS_D)
{
if (!PHAR_G(request_init)) {
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
}
PHAR_G(intercepted) = 1;
}
/* }}} */
/* {{{ void phar_release_functions(TSRMLS_D) */
void phar_release_functions(TSRMLS_D)
{
PHAR_G(intercepted) = 0;
}
/* }}} */
/* {{{ void phar_intercept_functions_init(TSRMLS_D) */
#define PHAR_INTERCEPT(func) \
PHAR_G(orig_##func) = NULL; \
if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
@@ -1002,17 +1062,10 @@ PharFileFunction(phar_stat, FS_STAT, orig_stat)
orig->internal_function.handler = phar_##func; \
}
void phar_intercept_functions(TSRMLS_D)
void phar_intercept_functions_init(TSRMLS_D)
{
zend_function *orig;
if (!PHAR_G(request_init)) {
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
} else if (PHAR_G(orig_fopen)) {
/* don't double-intercept */
return;
}
PHAR_INTERCEPT(fopen);
PHAR_INTERCEPT(file_get_contents);
PHAR_INTERCEPT(is_file);
@@ -1035,17 +1088,18 @@ void phar_intercept_functions(TSRMLS_D)
PHAR_INTERCEPT(lstat);
PHAR_INTERCEPT(stat);
PHAR_INTERCEPT(readfile);
PHAR_G(intercepted) = 0;
}
/* }}} */
/* {{{ void phar_release_functions(TSRMLS_D) */
/* {{{ void phar_intercept_functions_shutdown(TSRMLS_D) */
#define PHAR_RELEASE(func) \
if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
orig->internal_function.handler = PHAR_G(orig_##func); \
} \
PHAR_G(orig_##func) = NULL;
void phar_release_functions(TSRMLS_D)
void phar_intercept_functions_shutdown(TSRMLS_D)
{
zend_function *orig;
@@ -1070,6 +1124,7 @@ void phar_release_functions(TSRMLS_D)
PHAR_RELEASE(lstat);
PHAR_RELEASE(stat);
PHAR_RELEASE(readfile);
PHAR_G(intercepted) = 0;
}
/* }}} */

View File

@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| 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, |
| that is bundled with this package in the file LICENSE, and is |
@@ -22,6 +22,8 @@
BEGIN_EXTERN_C()
void phar_intercept_functions(TSRMLS_D);
void phar_release_functions(TSRMLS_D);
void phar_intercept_functions_init(TSRMLS_D);
void phar_intercept_functions_shutdown(TSRMLS_D);
END_EXTERN_C()
/*

View File

@@ -4,18 +4,18 @@ $s = str_replace("\r", '', file_get_contents(dirname(__FILE__) . '/shortarc.php'
$s .= "\nExtract_Phar::go();\n__HALT_COMPILER();";
$news = '';
foreach (token_get_all($s) as $token) {
if (is_array($token)) {
if ($token[0] == T_COMMENT) {
$token[1] = '';
}
if ($token[0] == T_WHITESPACE) {
$n = str_repeat("\n", substr_count($token[1], "\n"));
$token[1] = strlen($n) ? $n : ' ';
}
$news .= $token[1];
} else {
$news .= $token;
}
if (is_array($token)) {
if ($token[0] == T_COMMENT) {
$token[1] = '';
}
if ($token[0] == T_WHITESPACE) {
$n = str_repeat("\n", substr_count($token[1], "\n"));
$token[1] = strlen($n) ? $n : ' ';
}
$news .= $token[1];
} else {
$news .= $token;
}
}
$s = $news . ' ?>';
$slen = strlen($s) - strlen('index.php') - strlen("000");
@@ -34,7 +34,7 @@ $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, |
| that is bundled with this package in the file LICENSE, and is |
@@ -57,50 +57,50 @@ $s1split = str_split($s1, 2046);
$s3split = str_split($s3, 2046);
$took = false;
foreach ($s1split as $i => $chunk) {
if ($took) {
$s1split[$i] = substr($chunk, 1);
$took = false;
}
if ($chunk[strlen($chunk) - 1] == '\\') {
$s1split[$i] .= $s1split[$i + 1][0];
$took = true;
}
if ($took) {
$s1split[$i] = substr($chunk, 1);
$took = false;
}
if ($chunk[strlen($chunk) - 1] == '\\') {
$s1split[$i] .= $s1split[$i + 1][0];
$took = true;
}
}
foreach ($s3split as $i => $chunk) {
if ($took) {
$s3split[$i] = substr($chunk, 1);
$took = false;
}
if ($chunk[strlen($chunk) - 1] == '\\') {
$s3split[$i] .= $s3split[$i + 1][0];
$took = true;
}
if ($took) {
$s3split[$i] = substr($chunk, 1);
$took = false;
}
if ($chunk[strlen($chunk) - 1] == '\\') {
$s3split[$i] .= $s3split[$i + 1][0];
$took = true;
}
}
$stub .= "\tstatic const char newstub0[] = \"" . $webs . '";
';
foreach ($s1split as $i => $chunk) {
$s1count = $i + 1;
$stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '";
$s1count = $i + 1;
$stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '";
';
}
$stub .= "\tstatic const char newstub2[] = \"" . $s2 . "\";
";
foreach ($s3split as $i => $chunk) {
$s3count = $i + 1;
$stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '";
$s3count = $i + 1;
$stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '";
';
}
$stub .= "\n\tstatic const int newstub_len = " . $slen . ";
\t*len = spprintf(stub, name_len + web_len + newstub_len, \"%s%s" . str_repeat('%s', $s1count) . '%s%s%d'
. str_repeat('%s', $s3count) . '", newstub0, web';
. str_repeat('%s', $s3count) . '", newstub0, web';
foreach ($s1split as $i => $unused) {
$stub .= ', newstub1_' . $i;
$stub .= ', newstub1_' . $i;
}
$stub .= ', index_php, newstub2';
$stub .= ", name_len + web_len + newstub_len";
foreach ($s3split as $i => $unused) {
$stub .= ', newstub3_' . $i;
$stub .= ', newstub3_' . $i;
}
$stub .= ");
}";

View File

@@ -53,29 +53,29 @@ require_once 'PEAR/PackageFileManager2.php';
PEAR::setErrorHandling(PEAR_ERROR_DIE);
$options = array(
'filelistgenerator' => 'CVS',
'changelogoldtonew' => false,
'simpleoutput' => true,
'baseinstalldir' => '/',
'packagedirectory' => dirname(__FILE__),
'packagefile' => 'package.xml',
'clearcontents' => true,
'ignore' => array('package*.php', 'package*.xml'),
'dir_roles' => array(
'docs' => 'doc',
'examples' => 'doc',
'tests' => 'test',
'phar' => 'src',
),
'exceptions' => array(
'CREDITS' => 'doc',
'EXPERIMENTAL' => 'doc',
'LICENSE' => 'doc',
'Makefile.frag' => 'src',
'phar_path_check.re' => 'src',
'TODO' => 'doc',
'phar.phar' => 'script',
),
'filelistgenerator' => 'CVS',
'changelogoldtonew' => false,
'simpleoutput' => true,
'baseinstalldir' => '/',
'packagedirectory' => dirname(__FILE__),
'packagefile' => 'package.xml',
'clearcontents' => true,
'ignore' => array('package*.php', 'package*.xml'),
'dir_roles' => array(
'docs' => 'doc',
'examples' => 'doc',
'tests' => 'test',
'phar' => 'src',
),
'exceptions' => array(
'CREDITS' => 'doc',
'EXPERIMENTAL' => 'doc',
'LICENSE' => 'doc',
'Makefile.frag' => 'src',
'phar_path_check.re' => 'src',
'TODO' => 'doc',
'phar.phar' => 'script',
),
);
$package = PEAR_PackageFileManager2::importOptions(dirname(__FILE__) . '/package.xml', $options);
@@ -100,9 +100,9 @@ $package->setNotes("\n$notes\n");
$package->generateContents();
if (isset($_GET['make']) || (isset($_SERVER['argv']) && @$_SERVER['argv'][1] == 'make')) {
$package->writePackageFile();
$package->writePackageFile();
} else {
$package->debugPackageFile();
$package->debugPackageFile();
}
?>

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| 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, |
| that is bundled with this package in the file LICENSE, and is |
@@ -72,7 +72,16 @@
#endif
#ifndef E_RECOVERABLE_ERROR
#define E_RECOVERABLE_ERROR E_ERROR
# define E_RECOVERABLE_ERROR E_ERROR
#endif
#ifndef pestrndup
# define pestrndup(s, length, persistent) ((persistent)?zend_strndup((s),(length)):estrndup((s),(length)))
#endif
#ifndef ALLOC_PERMANENT_ZVAL
# define ALLOC_PERMANENT_ZVAL(z) \
(z) = (zval*)malloc(sizeof(zval))
#endif
/* PHP_ because this is public information via MINFO */
@@ -103,7 +112,7 @@
#define PHAR_SIG_SHA1 0x0002
#define PHAR_SIG_SHA256 0x0003
#define PHAR_SIG_SHA512 0x0004
#define PHAR_SIG_PGP 0x0010
#define PHAR_SIG_OPENSSL 0x0010
/* flags byte for each file adheres to these bitmasks.
All unused values are reserved */
@@ -132,15 +141,29 @@
#define TAR_DIR '5'
#define TAR_NEW '8'
#define PHAR_MUNG_PHP_SELF (1<<0)
#define PHAR_MUNG_REQUEST_URI (1<<1)
#define PHAR_MUNG_SCRIPT_NAME (1<<2)
#define PHAR_MUNG_SCRIPT_FILENAME (1<<3)
typedef struct _phar_entry_fp phar_entry_fp;
typedef struct _phar_archive_data phar_archive_data;
ZEND_BEGIN_MODULE_GLOBALS(phar)
HashTable phar_fname_map;
/* for cached phars, this is a per-process store of fp/ufp */
phar_entry_fp *cached_fp;
HashTable phar_alias_map;
HashTable phar_SERVER_mung_list;
int phar_SERVER_mung_list;
int readonly;
char* cache_list;
int manifest_cached;
int persist;
int has_zlib;
int has_bz2;
zend_bool readonly_orig;
zend_bool require_hash_orig;
zend_bool intercepted;
int request_init;
int require_hash;
int request_done;
@@ -171,6 +194,15 @@ ZEND_BEGIN_MODULE_GLOBALS(phar)
char* cwd;
int cwd_len;
int cwd_init;
char *openssl_privatekey;
int openssl_privatekey_len;
/* phar_get_archive cache */
char* last_phar_name;
int last_phar_name_len;
char* last_alias;
int last_alias_len;
phar_archive_data* last_phar;
HashTable mime_types;
ZEND_END_MODULE_GLOBALS(phar)
ZEND_EXTERN_MODULE_GLOBALS(phar)
@@ -213,7 +245,6 @@ enum phar_fp_type {
PHAR_TMP
};
typedef struct _phar_archive_data phar_archive_data;
/* entry for one file in a phar file */
typedef struct _phar_entry_info {
/* first bytes are exactly as in file */
@@ -226,6 +257,7 @@ typedef struct _phar_entry_info {
/* when changing compression, save old flags in case fp is NULL */
php_uint32 old_flags;
zval *metadata;
int metadata_len; /* only used for cached manifests */
php_uint32 filename_len;
char *filename;
enum phar_fp_type fp_type;
@@ -256,6 +288,12 @@ typedef struct _phar_entry_info {
char tar_type;
/* zip-based phar file stuff */
int is_zip:1;
/* for cached phar entries */
int is_persistent:1;
/* position in the manifest */
uint manifest_pos;
/* for stat */
unsigned short inode;
} phar_entry_info;
/* information about a phar file (the archive itself) */
@@ -271,6 +309,8 @@ struct _phar_archive_data {
size_t internal_file_start;
size_t halt_offset;
HashTable manifest;
/* hash of virtual directories, as in path/to/file.txt has path/to and path as virtual directories */
HashTable virtual_dirs;
/* hash of mounted directory paths */
HashTable mounted_dirs;
php_uint32 flags;
@@ -284,6 +324,7 @@ struct _phar_archive_data {
int sig_len;
char *signature;
zval *metadata;
int metadata_len; /* only used for cached manifests */
/* if 1, then this alias was manually specified by the user and is not a permanent alias */
int is_temporary_alias:1;
int is_modified:1;
@@ -297,8 +338,130 @@ struct _phar_archive_data {
int is_tar:1;
/* PharData variables */
int is_data:1;
/* for cached phar manifests */
int is_persistent:1;
uint phar_pos;
};
typedef struct _phar_entry_fp_info {
enum phar_fp_type fp_type;
/* offset within fp of the file contents */
long offset;
} phar_entry_fp_info;
struct _phar_entry_fp {
php_stream *fp;
php_stream *ufp;
phar_entry_fp_info *manifest;
};
static inline php_stream *phar_get_entrypfp(phar_entry_info *entry TSRMLS_DC)
{
if (!entry->is_persistent) {
return entry->phar->fp;
}
return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp;
}
static inline php_stream *phar_get_entrypufp(phar_entry_info *entry TSRMLS_DC)
{
if (!entry->is_persistent) {
return entry->phar->ufp;
}
return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp;
}
static inline void phar_set_entrypfp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
{
if (!entry->phar->is_persistent) {
entry->phar->fp = fp;
return;
}
PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp = fp;
}
static inline void phar_set_entrypufp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
{
if (!entry->phar->is_persistent) {
entry->phar->ufp = fp;
return;
}
PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp = fp;
}
static inline php_stream *phar_get_pharfp(phar_archive_data *phar TSRMLS_DC)
{
if (!phar->is_persistent) {
return phar->fp;
}
return PHAR_GLOBALS->cached_fp[phar->phar_pos].fp;
}
static inline php_stream *phar_get_pharufp(phar_archive_data *phar TSRMLS_DC)
{
if (!phar->is_persistent) {
return phar->ufp;
}
return PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp;
}
static inline void phar_set_pharfp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
{
if (!phar->is_persistent) {
phar->fp = fp;
return;
}
PHAR_GLOBALS->cached_fp[phar->phar_pos].fp = fp;
}
static inline void phar_set_pharufp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
{
if (!phar->is_persistent) {
phar->ufp = fp;
return;
}
PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp = fp;
}
static inline void phar_set_fp_type(phar_entry_info *entry, enum phar_fp_type type, off_t offset TSRMLS_DC)
{
phar_entry_fp_info *data;
if (!entry->is_persistent) {
entry->fp_type = type;
entry->offset = offset;
return;
}
data = &(PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos]);
data->fp_type = type;
data->offset = offset;
}
static inline enum phar_fp_type phar_get_fp_type(phar_entry_info *entry TSRMLS_DC)
{
if (!entry->is_persistent) {
return entry->fp_type;
}
return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type;
}
static inline off_t phar_get_fp_offset(phar_entry_info *entry TSRMLS_DC)
{
if (!entry->is_persistent) {
return entry->offset;
}
if (PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type == PHAR_FP) {
if (!PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset) {
PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset = entry->offset;
}
}
return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset;
}
#define PHAR_MIME_PHP '\0'
#define PHAR_MIME_PHPS '\1'
#define PHAR_MIME_OTHER '\2'
@@ -330,8 +493,8 @@ union _phar_archive_object {
zend_object std;
spl_filesystem_object spl;
struct {
zend_object std;
phar_archive_data *archive;
zend_object std;
phar_archive_data *archive;
} arc;
};
#endif
@@ -342,8 +505,8 @@ union _phar_entry_object {
zend_object std;
spl_filesystem_object spl;
struct {
zend_object std;
phar_entry_info *entry;
zend_object std;
phar_entry_info *entry;
} ent;
};
#endif
@@ -357,11 +520,15 @@ extern char *(*phar_save_resolve_path)(const char *filename, int filename_len TS
#if PHP_VERSION_ID >= 60000
typedef zstr phar_zstr;
#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
typedef char *phar_zstr;
#define PHAR_STR(a, b) \
b = a;
#define PHAR_ZSTR(a, b) \
b = a;
#endif
BEGIN_EXTERN_C()
@@ -391,6 +558,17 @@ static inline int phar_validate_alias(const char *alias, int alias_len) /* {{{ *
}
/* }}} */
static inline void phar_set_inode(phar_entry_info *entry TSRMLS_DC) /* {{{ */
{
char tmp[MAXPATHLEN];
int tmp_len;
tmp_len = entry->filename_len + entry->phar->fname_len;
memcpy(tmp, entry->phar->fname, entry->phar->fname_len);
memcpy(tmp + entry->phar->fname_len, entry->filename, entry->filename_len);
entry->inode = (unsigned short)zend_get_hash_value(tmp, tmp_len);
}
/* }}} */
void phar_request_initialize(TSRMLS_D);
@@ -405,12 +583,15 @@ int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_
int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC);
int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC);
int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC);
int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC);
/* utility functions */
char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC);
char *phar_decompress_filter(phar_entry_info * entry, int return_unknown);
char *phar_compress_filter(phar_entry_info * entry, int return_unknown);
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC);
int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC);
char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
@@ -426,6 +607,7 @@ phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC);
int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC);
int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC);
int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC);
/* tar functions in tar.c */
int phar_is_tar(char *buf, char *fname);
@@ -441,6 +623,9 @@ int phar_zip_flush(phar_archive_data *archive, char *user_stub, long len, int de
#ifdef PHAR_MAIN
static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
extern php_stream_wrapper php_stream_phar_wrapper;
#else
extern HashTable cached_phars;
extern HashTable cached_alias;
#endif
int phar_archive_delref(phar_archive_data *phar TSRMLS_DC);
@@ -451,7 +636,7 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in
phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC);
int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC);
int phar_flush(phar_archive_data *archive, char *user_stub, long len, int convert, char **error TSRMLS_DC);
int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC);
int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC);
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC);
typedef enum {

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
+----------------------------------------------------------------------+
| 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, |
| 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 |
+----------------------------------------------------------------------+
| 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, |
| 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 |
+----------------------------------------------------------------------+
| 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, |
| that is bundled with this package in the file LICENSE, and is |
@@ -22,7 +22,7 @@
#ifndef 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"
extern zend_module_entry phar_module_entry;
@@ -34,7 +34,7 @@ extern zend_module_entry phar_module_entry;
#define PHP_PHAR_API
#endif
#endif /* PHP_PHAR_H */
#endif /* PHP_PHAR_H */
/*

View File

@@ -35,22 +35,22 @@ php_stream_ops phar_ops = {
};
php_stream_wrapper_ops phar_stream_wops = {
phar_wrapper_open_url,
NULL, /* phar_wrapper_close */
NULL, /* phar_wrapper_stat, */
phar_wrapper_stat, /* stat_url */
phar_wrapper_open_dir, /* opendir */
"phar",
phar_wrapper_unlink, /* unlink */
phar_wrapper_rename, /* rename */
phar_wrapper_mkdir, /* create directory */
phar_wrapper_rmdir, /* remove directory */
phar_wrapper_open_url,
NULL, /* phar_wrapper_close */
NULL, /* phar_wrapper_stat, */
phar_wrapper_stat, /* stat_url */
phar_wrapper_open_dir, /* opendir */
"phar",
phar_wrapper_unlink, /* unlink */
phar_wrapper_rename, /* rename */
phar_wrapper_mkdir, /* create directory */
phar_wrapper_rmdir, /* remove directory */
};
php_stream_wrapper php_stream_phar_wrapper = {
&phar_stream_wops,
NULL,
0 /* is_url */
php_stream_wrapper php_stream_phar_wrapper = {
&phar_stream_wops,
NULL,
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)) {
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 (!(options & PHP_STREAM_URL_STAT_QUIET)) {
if (arch && !entry) {
@@ -101,7 +101,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
}
#endif
if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
phar_archive_data **pphar = NULL;
phar_archive_data **pphar = NULL, *phar;
if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
pphar = NULL;
@@ -113,7 +113,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, &phar, &error TSRMLS_CC) == FAILURE)
{
if (error) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
@@ -124,6 +124,17 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
if (error) {
spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", resource->host);
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
}
efree(error);
}
php_url_free(resource);
return NULL;
}
} else {
if (phar_open_from_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
{
@@ -136,7 +147,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
}
}
return resource;
}
/* }}} */
@@ -146,6 +157,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
*/
static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
{
phar_archive_data *phar;
phar_entry_data *idata;
char *internal_file;
char *error;
@@ -223,8 +235,55 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
}
return fpf;
} else {
if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) {
/* retrieve the stub */
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, NULL TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "file %s is not a valid phar archive");
efree(internal_file);
php_url_free(resource);
return NULL;
}
if (phar->is_tar || phar->is_zip) {
if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, ".phar/stub.php", sizeof(".phar/stub.php")-1, "r", 0, &error, 0 TSRMLS_CC)) || !idata) {
goto idata_error;
}
efree(internal_file);
if (opened_path) {
spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
}
php_url_free(resource);
goto phar_stub;
} else {
phar_entry_info *entry;
entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
entry->is_temp_dir = 1;
entry->filename = "";
entry->filename_len = 0;
entry->phar = phar;
entry->offset = entry->offset_abs = 0;
entry->compressed_filesize = entry->uncompressed_filesize = phar->halt_offset;
entry->is_crc_checked = 1;
idata = (phar_entry_data *) ecalloc(1, sizeof(phar_entry_data));
idata->fp = phar_get_pharfp(phar TSRMLS_CC);
idata->phar = phar;
idata->internal_file = entry;
if (!phar->is_persistent) {
++(entry->phar->refcount);
}
++(entry->fp_refcount);
php_url_free(resource);
if (opened_path) {
spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
}
efree(internal_file);
goto phar_stub;
}
}
/* read-only access is allowed to magic files in .phar directory */
if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error, 0 TSRMLS_CC)) || !idata) {
idata_error:
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
efree(error);
@@ -237,7 +296,6 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
}
}
php_url_free(resource);
#if MBO_0
fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
fprintf(stderr, "Filename: %s\n", internal_file);
@@ -272,11 +330,12 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
PHAR_G(cwd) = NULL;
}
}
fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
if (opened_path) {
spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
}
efree(internal_file);
phar_stub:
fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
return fpf;
}
/* }}} */
@@ -286,8 +345,15 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
*/
static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
{
phar_entry_info *entry = ((phar_entry_data *)stream->abstract)->internal_file;
int is_temp_dir = entry->is_temp_dir;
phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC);
if (is_temp_dir) {
/* phar archive stub, free it */
efree(entry);
}
return 0;
}
/* }}} */
@@ -299,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;
size_t got;
if (data->internal_file->is_deleted) {
stream->eof = 1;
return 0;
@@ -312,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;
stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize);
return got;
}
/* }}} */
@@ -402,8 +467,6 @@ static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb,
zend_bool is_temp_dir, char *alias, int alias_len TSRMLS_DC)
{
char *tmp;
int tmp_len;
memset(ssb, 0, sizeof(php_stream_statbuf));
if (!is_temp_dir && !data->is_dir) {
@@ -454,23 +517,12 @@ void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_stat
ssb->sb.st_nlink = 1;
ssb->sb.st_rdev = -1;
if (data) {
tmp_len = data->filename_len + alias_len;
} else {
tmp_len = alias_len + 1;
}
tmp = (char *) emalloc(tmp_len);
memcpy(tmp, alias, alias_len);
if (data) {
memcpy(tmp + alias_len, data->filename, data->filename_len);
} else {
*(tmp+alias_len) = '/';
}
/* this is only for APC, so use /dev/null device - no chance of conflict there! */
ssb->sb.st_dev = 0xc;
/* generate unique inode number for alias/filename, so no phars will conflict */
ssb->sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
efree(tmp);
if (!is_temp_dir) {
ssb->sb.st_ino = data->inode;
}
#ifndef PHP_WIN32
ssb->sb.st_blksize = -1;
ssb->sb.st_blocks = -1;
@@ -502,10 +554,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
{
php_url *resource = NULL;
phar_zstr key;
char *internal_file, *error, *str_key;
uint keylen;
ulong unused;
char *internal_file, *error;
phar_archive_data *phar;
phar_entry_info *entry;
uint host_len;
@@ -557,76 +606,62 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
} else {
/* search for directory (partial match of a file) */
zend_hash_internal_pointer_reset(&phar->manifest);
while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
if (HASH_KEY_NON_EXISTANT !=
zend_hash_get_current_key_ex(
&phar->manifest, &key, &keylen, &unused, 0, NULL)) {
PHAR_STR(key, str_key);
if (keylen >= (uint)internal_file_len && 0 == memcmp(internal_file, str_key, internal_file_len)) {
/* directory found, all dirs have the same stat */
if (str_key[internal_file_len] == '/') {
phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
}
}
}
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
}
if (zend_hash_exists(&(phar->virtual_dirs), internal_file, internal_file_len)) {
phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
}
/* check for mounted directories */
if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
phar_zstr key;
char *str_key;
ulong unused;
uint keylen;
HashPosition pos;
zend_hash_internal_pointer_reset_ex(&phar->mounted_dirs, &pos);
while (FAILURE != zend_hash_has_more_elements_ex(&phar->mounted_dirs, &pos)) {
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, &pos)) {
break;
}
}
/* check for mounted directories */
if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
phar_zstr key;
char *str_key;
ulong unused;
uint keylen;
zend_hash_internal_pointer_reset(&phar->mounted_dirs);
while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
break;
PHAR_STR(key, str_key);
if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue;
} else {
char *test;
int test_len;
phar_entry_info *entry;
php_stream_statbuf ssbi;
if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
goto free_resource;
}
PHAR_STR(key, str_key);
if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
continue;
} else {
char *test;
int test_len;
phar_entry_info *entry;
php_stream_statbuf ssbi;
if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
goto free_resource;
}
if (!entry->tmp || !entry->is_mounted) {
goto free_resource;
}
test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
efree(test);
continue;
}
/* mount the file/directory just in time */
if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
efree(test);
goto free_resource;
}
if (!entry->tmp || !entry->is_mounted) {
goto free_resource;
}
test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
efree(test);
if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
goto free_resource;
}
phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue;
}
/* mount the file/directory just in time */
if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
efree(test);
goto free_resource;
}
efree(test);
if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
goto free_resource;
}
phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
}
}
}
free_resource:
php_url_free(resource);
return FAILURE;
@@ -692,7 +727,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
efree(error);
}
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);
efree(internal_file);
php_url_free(resource);
@@ -717,6 +752,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
phar_archive_data *phar, *pfrom, *pto;
phar_entry_info *entry;
uint host_len;
int is_dir = 0;
int is_modified = 0;
error = NULL;
@@ -767,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);
return 0;
}
if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
php_url_free(resource_from);
php_url_free(resource_to);
@@ -790,7 +827,6 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
}
host_len = strlen(resource_from->host);
phar_request_initialize(TSRMLS_C);
if (SUCCESS != phar_get_archive(&phar, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
php_url_free(resource_from);
@@ -800,6 +836,13 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
return 0;
}
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
php_url_free(resource_from);
php_url_free(resource_to);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to);
return 0;
}
if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) {
phar_entry_info new, *source;
@@ -831,20 +874,122 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
return 0;
}
is_modified = 1;
entry->is_modified = 1;
entry->filename_len = strlen(entry->filename);
is_dir = entry->is_dir;
} else {
is_dir = zend_hash_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1);
}
/* Rename directory. Update all nested paths */
if (is_dir) {
int key_type;
phar_zstr key, new_key;
char *str_key, *new_str_key;
uint key_len, new_key_len;
ulong unused;
uint from_len = strlen(resource_from->path+1);
uint to_len = strlen(resource_to->path+1);
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)) &&
SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry);
zend_hash_move_forward(&phar->manifest)) {
PHAR_STR(key, str_key);
if (!entry->is_deleted &&
key_len > from_len &&
memcmp(str_key, resource_from->path+1, from_len) == 0 &&
IS_SLASH(str_key[from_len])) {
new_key_len = key_len + to_len - from_len;
new_str_key = emalloc(new_key_len+1);
memcpy(new_str_key, resource_to->path + 1, to_len);
memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
new_str_key[new_key_len] = 0;
is_modified = 1;
entry->is_modified = 1;
efree(entry->filename);
entry->filename = new_str_key;
entry->filename_len = new_key_len;
PHAR_ZSTR(new_str_key, new_key);
zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL);
efree(new_str_key);
}
}
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));
zend_hash_move_forward(&phar->virtual_dirs)) {
PHAR_STR(key, str_key);
if (key_len >= from_len &&
memcmp(str_key, resource_from->path+1, from_len) == 0 &&
(key_len == from_len || IS_SLASH(str_key[from_len]))) {
new_key_len = key_len + to_len - from_len;
new_str_key = emalloc(new_key_len+1);
memcpy(new_str_key, resource_to->path + 1, to_len);
memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
new_str_key[new_key_len] = 0;
PHAR_ZSTR(new_str_key, new_key);
zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, NULL);
efree(new_str_key);
}
}
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)) &&
SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry);
zend_hash_move_forward(&phar->mounted_dirs)) {
PHAR_STR(key, str_key);
if (key_len >= from_len &&
memcmp(str_key, resource_from->path+1, from_len) == 0 &&
(key_len == from_len || IS_SLASH(str_key[from_len]))) {
new_key_len = key_len + to_len - from_len;
new_str_key = emalloc(new_key_len+1);
memcpy(new_str_key, resource_to->path + 1, to_len);
memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
new_str_key[new_key_len] = 0;
PHAR_ZSTR(new_str_key, new_key);
zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, NULL);
efree(new_str_key);
}
}
}
if (is_modified) {
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
if (error) {
php_url_free(resource_from);
php_url_free(resource_to);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
efree(error);
zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
return 0;
}
}
php_url_free(resource_from);
php_url_free(resource_to);
return 1;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| 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, |
| 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] == ' ') {
++i;
}
while (i < len &&
buf[i] >= '0' &&
buf[i] <= '7') {
while (i < len && buf[i] >= '0' && buf[i] <= '7') {
num = num * 8 + (buf[i] - '0');
++i;
}
return num;
}
/* }}} */
/* adapted from format_octal() in libarchive
*
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2003-2008 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,7 +97,7 @@ static php_uint32 phar_tar_checksum(char *buf, int len) /* {{{ */
}
/* }}} */
int phar_is_tar(char *buf, char *fname)
int phar_is_tar(char *buf, char *fname) /* {{{ */
{
tar_header *header = (tar_header *) buf;
php_uint32 checksum = phar_tar_number(header->checksum, sizeof(header->checksum));
@@ -119,6 +119,7 @@ int phar_is_tar(char *buf, char *fname)
}
return ret;
}
/* }}} */
int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
{
@@ -152,8 +153,9 @@ int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_l
}
return FAILURE;
}
/* }}} */
int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */
{
char *metadata;
size_t save = php_stream_tell(fp), read;
@@ -174,6 +176,7 @@ int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
php_stream_seek(fp, save, SEEK_SET);
return FAILURE;
}
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->metadata = NULL;
@@ -182,10 +185,12 @@ int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
mentry->metadata = entry->metadata;
entry->metadata = NULL;
}
efree(metadata);
php_stream_seek(fp, save, SEEK_SET);
return SUCCESS;
}
/* }}} */
int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
{
@@ -204,6 +209,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
totalsize = php_stream_tell(fp);
php_stream_seek(fp, 0, SEEK_SET);
read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname);
@@ -211,14 +217,19 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
php_stream_close(fp);
return FAILURE;
}
hdr = (tar_header*)buf;
old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0);
myphar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
zend_hash_init(&myphar->manifest, sizeof(phar_entry_info),
zend_get_hash_value, destroy_phar_manifest_entry, 0);
zend_hash_init(&myphar->mounted_dirs, sizeof(char *),
zend_get_hash_value, NULL, 0);
myphar = (phar_archive_data *) pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
myphar->is_persistent = PHAR_G(persist);
/* estimate number of entries, can't be certain with tar files */
zend_hash_init(&myphar->manifest, 2 + (totalsize >> 12),
zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)myphar->is_persistent);
zend_hash_init(&myphar->mounted_dirs, 5,
zend_get_hash_value, NULL, (zend_bool)myphar->is_persistent);
zend_hash_init(&myphar->virtual_dirs, 4 + (totalsize >> 11),
zend_get_hash_value, NULL, (zend_bool)myphar->is_persistent);
myphar->is_tar = 1;
/* remember whether this entire phar was compressed with gz/bzip2 */
myphar->flags = compression;
@@ -227,6 +238,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
entry.is_crc_checked = 1;
entry.phar = myphar;
pos += sizeof(buf);
do {
phar_entry_info *newentry;
@@ -242,6 +254,81 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
size = entry.uncompressed_filesize = entry.compressed_filesize =
phar_tar_number(hdr->size, sizeof(hdr->size));
if (((!old && hdr->prefix[0] == 0) || old) && strlen(hdr->name) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
size_t read;
if (size > 511) {
if (error) {
spprintf(error, 4096, "phar error: tar-based phar \"%s\" has signature that is larger than 511 bytes, cannot process", fname);
}
bail:
php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
read = php_stream_read(fp, buf, size);
if (read != size) {
if (error) {
spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be read", fname);
}
goto bail;
}
#ifdef WORDS_BIGENDIAN
# define PHAR_GET_32(buffer) \
(((((unsigned char*)(buffer))[3]) << 24) \
| ((((unsigned char*)(buffer))[2]) << 16) \
| ((((unsigned char*)(buffer))[1]) << 8) \
| (((unsigned char*)(buffer))[0]))
#else
# define PHAR_GET_32(buffer) (php_uint32) *(buffer)
#endif
if (FAILURE == phar_verify_signature(fp, php_stream_tell(fp) - size - 512, PHAR_GET_32(buf), buf + 8, PHAR_GET_32(buf + 4), fname, &myphar->signature, &myphar->sig_len, error TSRMLS_CC)) {
if (error) {
char *save = *error;
spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be verified: %s", fname, save);
efree(save);
}
goto bail;
}
/* signature checked out, let's ensure this is the last file in the phar */
size = ((size+511)&~511) + 512;
if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) {
/* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek(fp, size, SEEK_CUR);
if ((uint)php_stream_tell(fp) > totalsize) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
}
php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
}
read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
}
php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
hdr = (tar_header*) buf;
sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) {
break;
}
if (error) {
spprintf(error, 4096, "phar error: \"%s\" has entries after signature, invalid phar", fname);
}
goto bail;
}
if (!old && hdr->prefix[0] != 0) {
char name[256];
@@ -252,32 +339,34 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
} else {
strcat(name, hdr->name);
}
entry.filename_len = strlen(hdr->prefix) + 100;
if (name[entry.filename_len - 1] == '/') {
/* some tar programs store directories with trailing slash */
entry.filename_len--;
}
entry.filename = estrndup(name, entry.filename_len);
entry.filename = pestrndup(name, entry.filename_len, myphar->is_persistent);
} else {
entry.filename = estrdup(hdr->name);
entry.filename = pestrdup(hdr->name, myphar->is_persistent);
entry.filename_len = strlen(entry.filename);
if (entry.filename[entry.filename_len - 1] == '/') {
/* some tar programs store directories with trailing slash */
entry.filename[entry.filename_len - 1] = '\0';
entry.filename_len--;
}
}
phar_add_virtual_dirs(myphar, entry.filename, entry.filename_len TSRMLS_CC);
if (sum1 != sum2) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename);
}
efree(entry.filename);
pefree(entry.filename, myphar->is_persistent);
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
@@ -286,13 +375,14 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
entry.fp_type = PHAR_FP;
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.is_persistent = myphar->is_persistent;
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
#endif
if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) {
entry.tar_type = TAR_DIR;
}
if (entry.tar_type == TAR_DIR) {
entry.is_dir = 1;
} else {
@@ -300,39 +390,39 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
}
entry.link = NULL;
if (entry.tar_type == TAR_LINK) {
if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
}
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
entry.link = estrdup(hdr->linkname);
} else if (entry.tar_type == TAR_SYMLINK) {
entry.link = estrdup(hdr->linkname);
}
phar_set_inode(&entry TSRMLS_CC);
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.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 (error) {
spprintf(error, 4096, "phar error: tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname, entry.filename);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
}
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;
/* found explicit alias */
@@ -341,14 +431,12 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
spprintf(error, 4096, "phar error: tar-based phar \"%s\" has alias that is larger than 511 bytes, cannot process", fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
read = php_stream_read(fp, buf, size);
if (read == size) {
buf[size] = '\0';
if (!phar_validate_alias(buf, size)) {
@@ -358,18 +446,17 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
buf[52] = '.';
buf[53] = '\0';
}
if (error) {
spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
actual_alias = estrndup(buf, size);
actual_alias = pestrndup(buf, size, myphar->is_persistent);
myphar->alias = actual_alias;
myphar->alias_len = size;
php_stream_seek(fp, pos, SEEK_SET);
@@ -377,16 +464,15 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
if (error) {
spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
}
size = (size+511)&~511;
if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) {
/* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek(fp, size, SEEK_CUR);
@@ -395,33 +481,39 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
}
read = php_stream_read(fp, buf, sizeof(buf));
if (read != sizeof(buf)) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
} while (read != 0);
myphar->fname = estrndup(fname, fname_len);
/* ensure signature set */
if (PHAR_G(require_hash) && !myphar->signature) {
php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC);
if (error) {
spprintf(error, 0, "tar-based phar \"%s\" does not have a signature", fname);
}
return FAILURE;
}
myphar->fname = pestrndup(fname, fname_len, myphar->is_persistent);
#ifdef PHP_WIN32
phar_unixify_path_separators(myphar->fname, fname_len);
#endif
myphar->fname_len = fname_len;
myphar->fp = fp;
p = strrchr(myphar->fname, '/');
if (zend_hash_exists(&(myphar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
@@ -439,25 +531,25 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
myphar->ext_len = (myphar->fname + fname_len) - myphar->ext;
}
}
myphar->fp = fp;
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 (error) {
spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname);
}
php_stream_close(fp);
zend_hash_destroy(&myphar->manifest);
myphar->manifest.arBuckets = 0;
zend_hash_destroy(&myphar->mounted_dirs);
myphar->mounted_dirs.arBuckets = 0;
efree(myphar);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
myphar = *actual;
if (actual_alias) {
phar_archive_data **fd_ptr;
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 != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) {
if (error) {
@@ -467,6 +559,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
return FAILURE;
}
}
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
} else {
phar_archive_data **fd_ptr;
@@ -481,18 +574,21 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
return FAILURE;
}
}
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
myphar->alias = estrndup(alias, alias_len);
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
myphar->alias = pestrndup(alias, alias_len, myphar->is_persistent);
myphar->alias_len = alias_len;
} else {
myphar->alias = estrndup(myphar->fname, fname_len);
myphar->alias = pestrndup(myphar->fname, fname_len, myphar->is_persistent);
myphar->alias_len = fname_len;
}
myphar->is_temporary_alias = 1;
}
if (pphar) {
*pphar = myphar;
}
return SUCCESS;
}
/* }}} */
@@ -505,7 +601,7 @@ struct _phar_pass_tar_info {
char **error;
};
int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ */
{
tar_header header;
size_t pos;
@@ -516,6 +612,7 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP;
}
if (entry->is_deleted) {
if (entry->fp_refcount <= 0) {
return ZEND_HASH_APPLY_REMOVE;
@@ -526,6 +623,7 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
}
memset((char *) &header, 0, sizeof(header));
if (entry->filename_len > 100) {
if (entry->filename_len > 255) {
if (fp->error) {
@@ -538,28 +636,35 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
} else {
memcpy(header.name, entry->filename, entry->filename_len);
}
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 (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);
}
return ZEND_HASH_APPLY_STOP;
}
if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) {
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);
}
return ZEND_HASH_APPLY_STOP;
}
/* calc checksum */
header.typeflag = entry->tar_type;
if (entry->link) {
strncpy(header.linkname, entry->link, strlen(entry->link));
}
strncpy(header.magic, "ustar", sizeof("ustar")-1);
strncpy(header.version, "00", sizeof("00")-1);
strncpy(header.checksum, " ", sizeof(" ")-1);
entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header));
if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) {
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);
@@ -569,12 +674,14 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
/* write header */
entry->header_offset = php_stream_tell(fp->new);
if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) {
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);
}
return ZEND_HASH_APPLY_STOP;
}
pos = php_stream_tell(fp->new); /* save start of file within tar */
/* write contents */
@@ -582,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)) {
return ZEND_HASH_APPLY_STOP;
}
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
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);
}
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 (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);
}
return ZEND_HASH_APPLY_STOP;
}
memset(padding, 0, 512);
php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
}
if (!entry->is_modified && entry->fp_refcount) {
/* open file pointers refer to this fp, do not free the stream */
switch (entry->fp_type) {
@@ -612,48 +722,57 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
}
entry->is_modified = 0;
if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
if (!entry->fp_refcount) {
php_stream_close(entry->fp);
}
entry->fp = NULL;
}
entry->fp_type = PHAR_FP;
/* note new location within tar */
entry->offset = entry->offset_abs = pos;
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
int phar_tar_setmetadata(zval *metadata, phar_entry_info *entry, char **error, php_stream *fp TSRMLS_DC)
int phar_tar_setmetadata(zval *metadata, phar_entry_info *entry, char **error, php_stream *fp TSRMLS_DC) /* {{{ */
{
php_serialize_data_t metadata_hash;
if (entry->metadata_str.c) {
smart_str_free(&entry->metadata_str);
}
entry->metadata_str.c = 0;
entry->metadata_str.len = 0;
PHP_VAR_SERIALIZE_INIT(metadata_hash);
php_var_serialize(&entry->metadata_str, &metadata, &metadata_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
entry->uncompressed_filesize = entry->compressed_filesize = entry->metadata_str.len;
if (entry->fp && entry->fp_type == PHAR_MOD) {
php_stream_close(entry->fp);
}
entry->fp_type = PHAR_MOD;
entry->is_modified = 1;
entry->fp = php_stream_fopen_tmpfile();
entry->offset = entry->offset_abs = 0;
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);
zend_hash_del(&(entry->phar->manifest), entry->filename, entry->filename_len);
return ZEND_HASH_APPLY_STOP;
}
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC)
int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC) /* {{{ */
{
int lookfor_len;
struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument;
@@ -677,13 +796,16 @@ int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC)
if (!entry->is_modified) {
return ZEND_HASH_APPLY_KEEP;
}
/* now we are dealing with regular files, so look for metadata */
lookfor_len = spprintf(&lookfor, 0, ".phar/.metadata/%s/.metadata.bin", entry->filename);
if (!entry->metadata) {
zend_hash_del(&(entry->phar->manifest), lookfor, lookfor_len);
efree(lookfor);
return ZEND_HASH_APPLY_KEEP;
}
if (SUCCESS == zend_hash_find(&(entry->phar->manifest), lookfor, lookfor_len, (void **)&metadata)) {
int ret;
ret = phar_tar_setmetadata(entry->metadata, metadata, error, fp TSRMLS_CC);
@@ -705,15 +827,16 @@ int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC)
return phar_tar_setmetadata(entry->metadata, metadata, error, fp TSRMLS_CC);
}
/* }}} */
int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
{
phar_entry_info entry = {0};
static const char newstub[] = "<?php // tar-based phar archive stub file\n__HALT_COMPILER();";
php_stream *oldfile, *newfile, *stubfile;
int closeoldfile, free_user_stub;
int closeoldfile, free_user_stub, signature_length;
struct _phar_pass_tar_info pass;
char *buf;
char *buf, *signature, sigbuf[8];
entry.flags = PHAR_ENT_PERM_DEF_FILE;
entry.timestamp = time(NULL);
@@ -724,6 +847,13 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
entry.phar = phar;
entry.fp_type = PHAR_MOD;
if (phar->is_persistent) {
if (error) {
spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname);
}
return EOF;
}
if (phar->is_data) {
goto nostub;
}
@@ -733,14 +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_len = sizeof(".phar/alias.txt")-1;
entry.fp = php_stream_fopen_tmpfile();
entry.crc32 = phar_tar_checksum(phar->alias, phar->alias_len);
if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
if (error) {
spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
}
return EOF;
}
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 (error) {
spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
@@ -778,8 +910,8 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else {
free_user_stub = 0;
}
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) {
if (error) {
spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname);
}
@@ -788,6 +920,7 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
return EOF;
}
len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5;
@@ -803,9 +936,11 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
php_stream_close(entry.fp);
return EOF;
}
entry.filename = estrndup(".phar/stub.php", 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);
if (free_user_stub) {
efree(user_stub);
}
@@ -850,9 +985,7 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
}
}
nostub:
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
@@ -861,7 +994,9 @@ nostub:
oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
closeoldfile = oldfile != NULL;
}
newfile = php_stream_fopen_tmpfile();
if (!newfile) {
if (error) {
spprintf(error, 0, "unable to create temporary file");
@@ -903,6 +1038,7 @@ nostub:
}
return EOF;
}
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);
if (closeoldfile) {
@@ -912,12 +1048,14 @@ nostub:
}
}
}
zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_setupmetadata, (void *) &pass TSRMLS_CC);
if (error && *error) {
if (closeoldfile) {
php_stream_close(oldfile);
}
/* on error in the hash iterator above, error is set */
php_stream_close(newfile);
return EOF;
@@ -925,6 +1063,67 @@ nostub:
zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
if (!phar->is_data || phar->sig_flags) {
if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, error TSRMLS_CC)) {
if (error) {
char *save = *error;
spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", save);
efree(save);
}
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
return EOF;
}
entry.filename = ".phar/signature.bin";
entry.filename_len = sizeof(".phar/signature.bin")-1;
entry.fp = php_stream_fopen_tmpfile();
#ifdef WORDS_BIGENDIAN
# define PHAR_SET_32(var, buffer) \
*(php_uint32 *)(var) = (((((unsigned char*)(buffer))[3]) << 24) \
| ((((unsigned char*)(buffer))[2]) << 16) \
| ((((unsigned char*)(buffer))[1]) << 8) \
| (((unsigned char*)(buffer))[0]))
#else
# define PHAR_SET_32(var, buffer) *(php_uint32 *)(var) = (php_uint32) (buffer)
#endif
PHAR_SET_32(sigbuf, phar->sig_flags);
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)) {
efree(signature);
if (error) {
spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname);
}
if (closeoldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
return EOF;
}
efree(signature);
entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
/* throw out return value and write the signature */
entry.filename_len = phar_tar_writeheaders((void *)&entry, (void *)&pass TSRMLS_CC);
if (error && *error) {
if (closeoldfile) {
php_stream_close(oldfile);
}
/* error is set by writeheaders */
php_stream_close(newfile);
return EOF;
}
} /* signature */
/* add final zero blocks */
buf = (char *) ecalloc(1024, 1);
php_stream_write(newfile, buf, 1024);
@@ -933,14 +1132,17 @@ nostub:
if (closeoldfile) {
php_stream_close(oldfile);
}
/* on error in the hash iterator above, error is set */
if (error && *error) {
php_stream_close(newfile);
return EOF;
}
if (phar->fp && pass.free_fp) {
php_stream_close(phar->fp);
}
if (phar->ufp) {
if (pass.free_ufp) {
php_stream_close(phar->ufp);
@@ -949,7 +1151,6 @@ nostub:
}
phar->is_brandnew = 0;
php_stream_rewind(newfile);
if (phar->donotflush) {
@@ -964,6 +1165,7 @@ nostub:
}
return EOF;
}
if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
php_stream_filter *filter;
/* to properly compress, we have to tell zlib to add a zlib header */
@@ -977,6 +1179,7 @@ nostub:
add_assoc_long(&filterparams, "window", MAX_WBITS + 16);
filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
zval_dtor(&filterparams);
if (!filter) {
/* copy contents uncompressed rather than lose them */
php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
@@ -986,6 +1189,7 @@ nostub:
}
return EOF;
}
php_stream_filter_append(&phar->fp->writefilters, filter);
php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
php_stream_filter_flush(filter, 1);
@@ -1013,3 +1217,12 @@ nostub:
return EOF;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@
# define PHAR_SET_16(buffer) (buffer)
#endif
static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC)
static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC) /* {{{ */
{
union {
phar_zip_extra_field_header header;
@@ -46,32 +46,41 @@ 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))) {
return FAILURE;
}
if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
/* skip to next header */
php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
len -= PHAR_GET_16(h.header.size) + 4;
continue;
}
/* unix3 header found */
read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
len -= read + 4;
if (sizeof(h.unix3) - sizeof(h.header) != read) {
return FAILURE;
}
if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
/* skip symlink filename - we may add this support in later */
php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR);
}
/* set permissions */
entry->flags &= PHAR_ENT_COMPRESSION_MASK;
if (entry->is_dir) {
entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
} else {
entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
}
} while (len);
return SUCCESS;
}
/* }}} */
/*
extracted from libzip
@@ -93,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
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -106,38 +115,40 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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;
time_t now;
struct tm *tm, tmbuf;
time_t now;
now = time(NULL);
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;
now = time(NULL);
tm = php_localtime_r(&now, &tmbuf);
tm->tm_hour = (dtime>>11)&31;
tm->tm_min = (dtime>>5)&63;
tm->tm_sec = (dtime<<1)&62;
tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
tm->tm_mon = ((ddate>>5)&15) - 1;
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);
*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);
tm = php_localtime_r(&time, &tmbuf);
*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);
}
/* }}} */
/**
* 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
*
* This is used by phar_open_from_fp to process a zip-based phar, but can be called
@@ -155,6 +166,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
char *p = buf, *ext, *actual_alias = NULL;
size = php_stream_tell(fp);
if (size > sizeof(locator) + 65536) {
/* seek to max comment length + end of central directory record */
size = sizeof(locator) + 65536;
@@ -168,6 +180,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
} else {
php_stream_seek(fp, 0, SEEK_SET);
}
if (!(read = php_stream_read(fp, buf, size))) {
php_stream_close(fp);
if (error) {
@@ -175,6 +188,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
}
return FAILURE;
}
while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
if (!memcmp(p + 1, "K\5\6", 3)) {
memcpy((void *)&locator, (void *) p, sizeof(locator));
@@ -186,6 +200,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
}
return FAILURE;
}
if (locator.counthere != locator.count) {
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);
@@ -193,45 +208,65 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias,
php_stream_close(fp);
return FAILURE;
}
mydata = ecalloc(sizeof(phar_archive_data), 1);
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist);
/* read in archive comment, if any */
if (locator.comment_len) {
char *metadata;
metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
efree(mydata);
pefree(mydata, mydata->is_persistent);
return FAILURE;
}
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) {
mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ALLOC_INIT_ZVAL(mydata->metadata);
ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 1);
if (entry.is_persistent) {
ALLOC_PERMANENT_ZVAL(mydata->metadata);
} else {
ALLOC_ZVAL(mydata->metadata);
}
INIT_ZVAL(*mydata->metadata);
metadata = pestrndup(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent);
ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 0);
}
} else {
mydata->metadata = NULL;
}
goto foundit;
}
}
php_stream_close(fp);
if (error) {
spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
}
return FAILURE;
foundit:
mydata->fname = estrndup(fname, fname_len);
mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
#ifdef PHP_WIN32
phar_unixify_path_separators(mydata->fname, fname_len);
#endif
mydata->is_zip = 1;
mydata->fname_len = fname_len;
ext = strrchr(mydata->fname, '/');
if (ext) {
mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
if (mydata->ext == ext) {
@@ -241,22 +276,28 @@ foundit:
mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
}
}
/* clean up on big-endian systems */
/* seek to central directory */
php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
/* read in central directory */
zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
zend_get_hash_value, destroy_phar_manifest_entry, 0);
zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
zend_get_hash_value, NULL, 0);
zend_hash_init(&mydata->manifest, PHAR_GET_16(locator.count),
zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
zend_hash_init(&mydata->mounted_dirs, 5,
zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
zend_hash_init(&mydata->virtual_dirs, PHAR_GET_16(locator.count) * 2,
zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
entry.phar = mydata;
entry.is_zip = 1;
entry.fp_type = PHAR_FP;
entry.is_persistent = mydata->is_persistent;
#define PHAR_ZIP_FAIL(errmsg) \
zend_hash_destroy(&mydata->manifest); \
mydata->manifest.arBuckets = 0; \
zend_hash_destroy(&mydata->mounted_dirs); \
mydata->mounted_dirs.arBuckets = 0; \
zend_hash_destroy(&mydata->virtual_dirs); \
mydata->virtual_dirs.arBuckets = 0; \
php_stream_close(fp); \
if (mydata->metadata) { \
zval_dtor(mydata->metadata); \
@@ -264,25 +305,31 @@ foundit:
if (error) { \
spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
} \
efree(mydata->fname); \
pefree(mydata->fname, mydata->is_persistent); \
if (mydata->alias) { \
efree(mydata->alias); \
pefree(mydata->alias, mydata->is_persistent); \
} \
efree(mydata); \
pefree(mydata, mydata->is_persistent); \
return FAILURE;
/* add each central directory item to the manifest */
for (i = 0; i < locator.count; ++i) {
for (i = 0; i < PHAR_GET_16(locator.count); ++i) {
phar_zip_central_dir_file zipentry;
if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
}
/* clean up for bigendian systems */
if (memcmp("PK\1\2", zipentry.signature, 4)) {
/* corrupted entry */
PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
}
if (entry.is_persistent) {
entry.manifest_pos = i;
}
entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
entry.crc32 = PHAR_GET_32(zipentry.crc32);
@@ -292,19 +339,25 @@ foundit:
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) +
PHAR_GET_16(zipentry.extra_len);
if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
PHAR_ZIP_FAIL("Cannot process encrypted zip files");
}
if (!PHAR_GET_16(zipentry.filename_len)) {
PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
}
entry.filename_len = PHAR_GET_16(zipentry.filename_len);
entry.filename = (char *) emalloc(entry.filename_len + 1);
entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent);
if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
}
entry.filename[entry.filename_len] = '\0';
if (entry.filename[entry.filename_len - 1] == '/') {
entry.is_dir = 1;
entry.filename_len--;
@@ -312,14 +365,18 @@ foundit:
} else {
entry.is_dir = 0;
}
phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len TSRMLS_CC);
if (PHAR_GET_16(zipentry.extra_len)) {
off_t loc = php_stream_tell(fp);
if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory");
}
php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
}
switch (zipentry.compressed) {
case PHAR_ZIP_COMP_NONE :
/* compression flag already set */
@@ -327,112 +384,134 @@ foundit:
case PHAR_ZIP_COMP_DEFLATE :
entry.flags |= PHAR_ENT_COMPRESSED_GZ;
if (!PHAR_G(has_zlib)) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("zlib extension is required");
}
break;
case PHAR_ZIP_COMP_BZIP2 :
entry.flags |= PHAR_ENT_COMPRESSED_BZ2;
if (!PHAR_G(has_bz2)) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("bzip2 extension is required");
}
break;
case 1 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip");
case 2 :
case 3 :
case 4 :
case 5 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip");
case 6 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip");
case 7 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip");
case 9 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip");
case 10 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip");
case 14 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip");
case 18 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip");
case 19 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip");
case 97 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip");
case 98 :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip");
default :
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
}
/* get file metadata */
if (zipentry.comment_len) {
if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in file comment, truncated");
}
p = buf;
entry.metadata_len = zipentry.comment_len;
if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) {
entry.metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ALLOC_INIT_ZVAL(entry.metadata);
ZVAL_STRINGL(entry.metadata, buf, PHAR_GET_16(zipentry.comment_len), 1);
if (entry.is_persistent) {
ALLOC_PERMANENT_ZVAL(entry.metadata);
} else {
ALLOC_ZVAL(entry.metadata);
}
INIT_ZVAL(*entry.metadata);
ZVAL_STRINGL(entry.metadata, pestrndup(buf, PHAR_GET_16(zipentry.comment_len), entry.is_persistent), PHAR_GET_16(zipentry.comment_len), 0);
}
} else {
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)) {
php_stream_filter *filter;
off_t saveloc;
/* archive alias found, seek to file contents, do not validate local header. Potentially risky, but
not very. */
/* archive alias found, seek to file contents, do not validate local header. Potentially risky, but not very. */
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);
mydata->alias_len = entry.uncompressed_filesize;
if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
if (!filter) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
}
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) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
} else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
php_stream_filter *filter;
filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
if (!filter) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
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);
if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
} else {
if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
efree(entry.filename);
pefree(entry.filename, entry.is_persistent);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
}
@@ -440,8 +519,11 @@ foundit:
/* return to central directory parsing */
php_stream_seek(fp, saveloc, SEEK_SET);
}
phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL);
}
mydata->fp = fp;
if (zend_hash_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
@@ -451,6 +533,7 @@ foundit:
}
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
if (actual_alias) {
phar_archive_data **fd_ptr;
@@ -462,7 +545,9 @@ foundit:
zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
return FAILURE;
}
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 != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
if (error) {
@@ -473,7 +558,13 @@ foundit:
return FAILURE;
}
}
mydata->alias = actual_alias;
mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
if (entry.is_persistent) {
efree(actual_alias);
}
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
} else {
phar_archive_data **fd_ptr;
@@ -488,18 +579,22 @@ foundit:
return FAILURE;
}
}
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
mydata->alias = estrndup(alias, alias_len);
mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
mydata->alias_len = alias_len;
} else {
mydata->alias = estrndup(mydata->fname, fname_len);
mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
mydata->alias_len = fname_len;
}
mydata->is_temporary_alias = 1;
}
if (pphar) {
*pphar = mydata;
}
return SUCCESS;
}
/* }}} */
@@ -537,6 +632,7 @@ int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_l
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);
}
return FAILURE;
}
/* }}} */
@@ -562,9 +658,11 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
entry = (phar_entry_info *)data;
p = (struct _phar_zip_pass*) arg;
if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP;
}
if (entry->is_deleted) {
if (entry->fp_refcount <= 0) {
return ZEND_HASH_APPLY_REMOVE;
@@ -573,6 +671,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
return ZEND_HASH_APPLY_KEEP;
}
}
memset(&local, 0, sizeof(local));
memset(&central, 0, sizeof(central));
memset(&perms, 0, sizeof(perms));
@@ -587,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 & 0xFF00 >> 8);
perms.crc32 = PHAR_SET_32(~(perms.crc32));
if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE);
}
if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2);
}
/* do not use PHAR_SET_16 on either field of the next line */
phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp);
central.timestamp = local.timestamp;
central.datestamp = local.datestamp;
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));
/* do extra field for perms later */
if (entry->is_modified) {
php_uint32 loc;
@@ -614,29 +717,36 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
}
goto continue_dir;
}
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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
}
efp = phar_get_efp(entry, 0 TSRMLS_CC);
efp = phar_get_efp(entry, 0 TSRMLS_CC);
newcrc32 = ~0;
for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
CRC32(newcrc32, php_stream_getc(efp));
}
entry->crc32 = ~newcrc32;
central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
/* not compressed */
entry->compressed_filesize = entry->uncompressed_filesize;
central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
goto not_compressed;
}
filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
if (!filter) {
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);
@@ -650,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
in read count */
entry->cfp = php_stream_fopen_tmpfile();
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);
return ZEND_HASH_APPLY_STOP;
}
php_stream_flush(efp);
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);
return ZEND_HASH_APPLY_STOP;
}
php_stream_filter_append((&entry->cfp->writefilters), filter);
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);
return ZEND_HASH_APPLY_STOP;
}
php_stream_filter_flush(filter, 1);
php_stream_flush(entry->cfp);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
@@ -677,6 +793,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
} else {
central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
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);
return ZEND_HASH_APPLY_STOP;
@@ -699,29 +816,36 @@ continue_dir:
PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
central.comment_len = PHAR_SET_16(entry->metadata_str.len);
}
entry->header_offset = php_stream_tell(p->filefp);
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))) {
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;
}
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);
return ZEND_HASH_APPLY_STOP;
}
if (entry->is_dir) {
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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
@@ -731,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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
}
}
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);
return ZEND_HASH_APPLY_STOP;
}
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);
return ZEND_HASH_APPLY_STOP;
}
if (entry->is_modified) {
if (entry->cfp) {
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);
return ZEND_HASH_APPLY_STOP;
}
php_stream_close(entry->cfp);
entry->cfp = NULL;
} else {
if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
return ZEND_HASH_APPLY_STOP;
}
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)) {
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;
}
}
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);
}
entry->is_modified = 0;
} else {
if (entry->fp_refcount) {
@@ -779,22 +912,27 @@ continue_dir:
break;
}
}
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);
return ZEND_HASH_APPLY_STOP;
}
}
entry->fp = NULL;
entry->offset = entry->offset_abs = offset;
entry->fp_type = PHAR_FP;
if (entry->metadata_str.c) {
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);
smart_str_free(&entry->metadata_str);
return ZEND_HASH_APPLY_STOP;
}
smart_str_free(&entry->metadata_str);
}
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
@@ -820,6 +958,13 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
entry.phar = phar;
entry.fp_type = PHAR_MOD;
if (phar->is_persistent) {
if (error) {
spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
}
return EOF;
}
if (phar->is_data) {
goto nostub;
}
@@ -827,15 +972,18 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
/* set alias */
if (!phar->is_temporary_alias && phar->alias_len) {
entry.fp = php_stream_fopen_tmpfile();
if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
if (error) {
spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
}
return EOF;
}
entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len;
entry.filename = estrndup(".phar/alias.txt", 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 (error) {
spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
@@ -845,6 +993,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else {
zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
}
/* register alias */
if (phar->alias_len) {
if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) {
@@ -862,12 +1011,15 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
return EOF;
}
if (len == -1) {
len = PHP_STREAM_COPY_ALL;
} else {
len = -len;
}
user_stub = 0;
if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
if (error) {
spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
@@ -878,6 +1030,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
} else {
free_user_stub = 0;
}
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{
if (error) {
@@ -888,6 +1041,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
return EOF;
}
len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5;
@@ -903,8 +1057,10 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
php_stream_close(entry.fp);
return EOF;
}
entry.filename = estrndup(".phar/stub.php", 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 (free_user_stub) {
efree(user_stub);
@@ -914,6 +1070,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
return EOF;
}
if (free_user_stub) {
efree(user_stub);
}
@@ -958,9 +1115,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
}
}
}
nostub:
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
@@ -973,6 +1128,7 @@ nostub:
/* save modified files to the zip */
pass.old = oldfile;
pass.filefp = php_stream_fopen_tmpfile();
if (!pass.filefp) {
if (closeoldfile) {
php_stream_close(oldfile);
@@ -982,7 +1138,9 @@ nostub:
}
return EOF;
}
pass.centralfp = php_stream_fopen_tmpfile();
if (!pass.centralfp) {
if (closeoldfile) {
php_stream_close(oldfile);
@@ -992,12 +1150,14 @@ nostub:
}
return EOF;
}
pass.free_fp = pass.free_ufp = 1;
memset(&eocd, 0, sizeof(eocd));
strncpy(eocd.signature, "PK\5\6", 4);
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);
if (temperr) {
php_stream_close(pass.filefp);
php_stream_close(pass.centralfp);
@@ -1015,6 +1175,7 @@ nostub:
eocd.cdir_size = php_stream_tell(pass.centralfp);
eocd.cdir_offset = php_stream_tell(pass.filefp);
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)) {
php_stream_close(pass.filefp);
php_stream_close(pass.centralfp);
@@ -1026,13 +1187,16 @@ nostub:
}
return EOF;
}
php_stream_close(pass.centralfp);
if (phar->metadata) {
/* set phar metadata */
PHP_VAR_SERIALIZE_INIT(metadata_hash);
php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
eocd.comment_len = PHAR_SET_16(main_metadata_str.len);
if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
php_stream_close(pass.filefp);
if (error) {
@@ -1044,6 +1208,7 @@ nostub:
smart_str_free(&main_metadata_str);
return EOF;
}
if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) {
php_stream_close(pass.filefp);
if (error) {
@@ -1055,7 +1220,9 @@ nostub:
smart_str_free(&main_metadata_str);
return EOF;
}
smart_str_free(&main_metadata_str);
} else {
if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
php_stream_close(pass.filefp);
@@ -1068,17 +1235,21 @@ nostub:
return EOF;
}
}
if (phar->fp && pass.free_fp) {
php_stream_close(phar->fp);
}
if (phar->ufp) {
if (pass.free_ufp) {
php_stream_close(phar->ufp);
}
phar->ufp = NULL;
}
/* re-open */
phar->is_brandnew = 0;
if (phar->donotflush) {
/* deferred flush */
phar->fp = pass.filefp;
@@ -1106,3 +1277,12 @@ nostub:
return EOF;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/