pharcmd: $(builddir)/phar.php $(builddir)/phar.phar
-$(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)"; \
+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 \
- export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \
- fi; \
- $$PHP $(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)"; \
+ $(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 \
- 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
+ $(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)
+ -@echo "Generating phar.php"
+ @$(PHP_PHARCMD_EXECUTABLE) $(PHP_PHARCMD_SETTINGS) $(srcdir)/build_precommand.php > $(builddir)/phar.php
+
+$(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)
* @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);
}
'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") {
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);
#!/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
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
// 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);
}
{
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;
}
/* }}} */
{
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);
}
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';
*/
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);
}
/* }}} */
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
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)) {
continue;
}
}
+
if (*dir == '/') {
/* root directory */
if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
}
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);
memcpy(entry, str_key, keylen);
entry[keylen] = '\0';
}
+
goto PHAR_ADD_ENTRY;
} else {
if (0 != memcmp(str_key, dir, dirlen)) {
}
}
}
+
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;
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) {
/**
* 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;
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);
php_url_free(resource);
return NULL;
}
+
if (error) {
efree(error);
}
+
if (*internal_file == '\0') {
/* root directory requested */
internal_file = estrndup(internal_file - 1, 1);
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;
return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
}
}
+
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
break;
}
/* 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))) {
}
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));
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;
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;
}
/* }}} */
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);
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
+ */
+----------------------------------------------------------------------+
| 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 |
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;
}
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;
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;
}
/* 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;
}
} 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);
goto skip_phar;
}
} else {
- if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+ if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
goto notfound;
}
}
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) {
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)) {
/* 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;
}
} 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);
goto skip_phar;
}
} else {
- if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+ if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
goto notfound;
}
}
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;
}
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)) {
/* 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;
}
} 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);
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;
}
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);
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;
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 */
+ 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;
+ 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;
+ 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;
- }
- }
+ goto statme_baby;
}
+ PHAR_G(cwd) = save;
+ PHAR_G(cwd_len) = save_len;
efree(entry);
efree(save2);
efree(arch);
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;
}
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;
#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); \
}
/* }}} */
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)
/* }}} */
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) {
}
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);
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;
}
}
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) {
}
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);
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;
}
}
}
}
skip_phar:
- PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ PHAR_G(orig_is_link)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
return;
}
/* }}} */
/* }}} */
/* {{{ 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)) { \
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);
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;
PHAR_RELEASE(lstat);
PHAR_RELEASE(stat);
PHAR_RELEASE(readfile);
+ PHAR_G(intercepted) = 0;
}
/* }}} */
+----------------------------------------------------------------------+
| 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 |
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()
/*
$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");
+----------------------------------------------------------------------+
| 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 |
$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 .= ");
}";
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);
$package->generateContents();
if (isset($_GET['make']) || (isset($_SERVER['argv']) && @$_SERVER['argv'][1] == 'make')) {
- $package->writePackageFile();
+ $package->writePackageFile();
} else {
- $package->debugPackageFile();
+ $package->debugPackageFile();
}
?>
#include "SAPI.h"
#include "func_interceptors.h"
+static void destroy_phar_data(void *pDest);
+
ZEND_DECLARE_MODULE_GLOBALS(phar)
#if PHP_VERSION_ID >= 50300
char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
if (!phar->is_data) {
phar->is_writeable = !keep;
}
+
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
-/* if the original value is 0 (disabled), then allow setting/unsetting at will
- otherwise, only allow 1 (enabled), and error on disabling */
+/* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
{
zend_bool old, ini;
old = PHAR_G(readonly_orig);
} else {
old = PHAR_G(require_hash_orig);
- }
+ }
if (new_value_length == 2 && !strcasecmp("on", new_value)) {
ini = (zend_bool) 1;
/* do not allow unsetting in runtime */
if (stage == ZEND_INI_STAGE_STARTUP) {
if (entry->name_length == 14) {
- PHAR_G(readonly_orig) = ini;
+ PHAR_G(readonly_orig) = ini;
} else {
PHAR_G(require_hash_orig) = ini;
- }
+ }
} else if (old && !ini) {
return FAILURE;
}
}
} else {
PHAR_G(require_hash) = ini;
- }
+ }
+
return SUCCESS;
}
/* }}}*/
+/* this global stores the global cached pre-parsed manifests */
+HashTable cached_phars;
+HashTable cached_alias;
+
+static void phar_split_cache_list(TSRMLS_D) /* {{{ */
+{
+ char *tmp;
+ char *key, *lasts, *end;
+ char ds[2];
+ phar_archive_data *phar;
+ uint i = 0;
+
+ if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) {
+ return;
+ }
+
+ ds[0] = DEFAULT_DIR_SEPARATOR;
+ ds[1] = '\0';
+ tmp = estrdup(PHAR_GLOBALS->cache_list);
+
+ /* fake request startup */
+ PHAR_GLOBALS->request_init = 1;
+ if (zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0) == SUCCESS) {
+ EG(regular_list).nNextFreeElement=1; /* we don't want resource id 0 */
+ }
+
+ PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
+ PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
+ /* these two are dummies and will be destroyed later */
+ zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
+ zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
+ /* these two are real and will be copied over cached_phars/cached_alias later */
+ zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
+ zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
+ PHAR_GLOBALS->manifest_cached = 1;
+ PHAR_GLOBALS->persist = 1;
+
+ for (key = php_strtok_r(tmp, ds, &lasts);
+ key;
+ key = php_strtok_r(NULL, ds, &lasts)) {
+ end = strchr(key, DEFAULT_DIR_SEPARATOR);
+
+ if (end) {
+ if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
+finish_up:
+ phar->phar_pos = i++;
+ php_stream_close(phar->fp);
+ phar->fp = NULL;
+ } else {
+finish_error:
+ PHAR_GLOBALS->persist = 0;
+ PHAR_GLOBALS->manifest_cached = 0;
+ efree(tmp);
+ zend_hash_destroy(&(PHAR_G(phar_fname_map)));
+ PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
+ zend_hash_destroy(&(PHAR_G(phar_alias_map)));
+ PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
+ zend_hash_destroy(&cached_phars);
+ zend_hash_destroy(&cached_alias);
+ zend_hash_graceful_reverse_destroy(&EG(regular_list));
+ memset(&EG(regular_list), 0, sizeof(HashTable));
+ /* free cached manifests */
+ PHAR_GLOBALS->request_init = 0;
+ return;
+ }
+ } else {
+ if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
+ goto finish_up;
+ } else {
+ goto finish_error;
+ }
+ }
+ }
+
+ PHAR_GLOBALS->persist = 0;
+ PHAR_GLOBALS->request_init = 0;
+ /* destroy dummy values from before */
+ zend_hash_destroy(&cached_phars);
+ zend_hash_destroy(&cached_alias);
+ cached_phars = PHAR_GLOBALS->phar_fname_map;
+ cached_alias = PHAR_GLOBALS->phar_alias_map;
+ PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
+ PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
+ zend_hash_graceful_reverse_destroy(&EG(regular_list));
+ memset(&EG(regular_list), 0, sizeof(HashTable));
+ efree(tmp);
+}
+/* }}} */
+
+ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
+{
+ PHAR_G(cache_list) = new_value;
+
+ if (stage == ZEND_INI_STAGE_STARTUP) {
+ phar_split_cache_list(TSRMLS_C);
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
PHP_INI_BEGIN()
- STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
+ STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
+ STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
PHP_INI_END()
/**
void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
{
if (phar->alias && phar->alias != phar->fname) {
- efree(phar->alias);
+ pefree(phar->alias, phar->is_persistent);
phar->alias = NULL;
}
+
if (phar->fname) {
- efree(phar->fname);
+ pefree(phar->fname, phar->is_persistent);
phar->fname = NULL;
}
+
if (phar->signature) {
- efree(phar->signature);
+ pefree(phar->signature, phar->is_persistent);
+ phar->signature = NULL;
}
+
if (phar->manifest.arBuckets) {
zend_hash_destroy(&phar->manifest);
phar->manifest.arBuckets = NULL;
}
+
if (phar->mounted_dirs.arBuckets) {
zend_hash_destroy(&phar->mounted_dirs);
phar->mounted_dirs.arBuckets = NULL;
}
+
+ if (phar->virtual_dirs.arBuckets) {
+ zend_hash_destroy(&phar->virtual_dirs);
+ phar->virtual_dirs.arBuckets = NULL;
+ }
+
if (phar->metadata) {
- zval_ptr_dtor(&phar->metadata);
+ if (phar->is_persistent) {
+ if (phar->metadata_len) {
+ /* for zip comments that are strings */
+ free(phar->metadata);
+ } else {
+ zval_internal_ptr_dtor(&phar->metadata);
+ }
+ } else {
+ zval_ptr_dtor(&phar->metadata);
+ }
+ phar->metadata_len = 0;
phar->metadata = 0;
}
+
if (phar->fp) {
php_stream_close(phar->fp);
phar->fp = 0;
}
+
if (phar->ufp) {
php_stream_close(phar->ufp);
- phar->fp = 0;
+ phar->ufp = 0;
}
- efree(phar);
+
+ pefree(phar, phar->is_persistent);
}
/* }}}*/
*/
int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
{
+ if (phar->is_persistent) {
+ return 0;
+ }
+
if (--phar->refcount < 0) {
if (PHAR_GLOBALS->request_done
|| zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
}
return 1;
} else if (!phar->refcount) {
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
/* close open file handle - allows removal or rename of
the file on windows, which has greedy locking
php_stream_close(phar->fp);
phar->fp = NULL;
}
+
if (!zend_hash_num_elements(&phar->manifest)) {
/* this is a new phar that has perhaps had an alias/metadata set, but has never
been flushed */
if (entry->fp_type != PHAR_TMP) {
return ZEND_HASH_APPLY_KEEP;
}
+
if (entry->fp && !entry->fp_refcount) {
php_stream_close(entry->fp);
entry->fp = NULL;
}
+
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
destroy_phar_data_only(pDest);
return;
}
+
zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
+
if (--phar_data->refcount < 0) {
phar_destroy_phar_data(phar_data TSRMLS_CC);
}
php_stream_close(entry->cfp);
entry->cfp = 0;
}
+
if (entry->fp) {
php_stream_close(entry->fp);
entry->fp = 0;
}
+
if (entry->metadata) {
- zval_ptr_dtor(&entry->metadata);
+ if (entry->is_persistent) {
+ if (entry->metadata_len) {
+ /* for zip comments that are strings */
+ free(entry->metadata);
+ } else {
+ zval_internal_ptr_dtor(&entry->metadata);
+ }
+ } else {
+ zval_ptr_dtor(&entry->metadata);
+ }
+ entry->metadata_len = 0;
entry->metadata = 0;
}
+
if (entry->metadata_str.c) {
smart_str_free(&entry->metadata_str);
entry->metadata_str.c = 0;
}
- efree(entry->filename);
+
+ pefree(entry->filename, entry->is_persistent);
+
if (entry->link) {
- efree(entry->link);
+ pefree(entry->link, entry->is_persistent);
entry->link = 0;
}
+
if (entry->tmp) {
- efree(entry->tmp);
+ pefree(entry->tmp, entry->is_persistent);
entry->tmp = 0;
}
}
{
int ret = 0;
- if (idata->internal_file) {
+ if (idata->internal_file && !idata->internal_file->is_persistent) {
if (--idata->internal_file->fp_refcount < 0) {
idata->internal_file->fp_refcount = 0;
}
+
if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
php_stream_close(idata->fp);
}
}
+
phar_archive_delref(idata->phar TSRMLS_CC);
efree(idata);
return ret;
phar_archive_data *phar;
phar = idata->phar;
+
if (idata->internal_file->fp_refcount < 2) {
if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
php_stream_close(idata->fp);
idata->internal_file->is_deleted = 1;
phar_entry_delref(idata TSRMLS_CC);
}
+
if (!phar->donotflush) {
phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
}
phar_destroy_phar_data(mydata TSRMLS_CC);\
}\
if (signature) {\
- efree(signature);\
+ pefree(signature, PHAR_G(persist));\
}\
MAPPHAR_ALLOC_FAIL(msg)
#ifdef PHP_WIN32
unixfname = estrndup(fname, fname_len);
phar_unixify_path_separators(unixfname, fname_len);
+
if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
&& ((alias && fname_len == phar->fname_len
&& !strncmp(unixfname, phar->fname, fname_len)) || !alias)
}
}
}
+
if (pphar) {
*pphar = phar;
}
+
return SUCCESS;
} else {
#ifdef PHP_WIN32
if (pphar) {
*pphar = NULL;
}
+
if (phar && error && !(options & REPORT_ERRORS)) {
efree(error);
}
+
return FAILURE;
}
}
} else {
buf_len = zip_metadata_len;
}
-
+
if (buf_len) {
- ALLOC_INIT_ZVAL(*metadata);
+ ALLOC_ZVAL(*metadata);
+ INIT_ZVAL(**metadata);
p = (const unsigned char*) *buffer;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
- if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
+
+ if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
zval_ptr_dtor(metadata);
*metadata = NULL;
return FAILURE;
}
+
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+
+ if (PHAR_G(persist)) {
+ /* lazy init metadata */
+ zval_ptr_dtor(metadata);
+ *metadata = (zval *) pemalloc(buf_len, 1);
+ memcpy(*metadata, *buffer, buf_len);
+ if (!zip_metadata_len) {
+ *buffer += buf_len;
+ }
+ return SUCCESS;
+ }
} else {
*metadata = NULL;
}
+
if (!zip_metadata_len) {
*buffer += buf_len;
}
+
return SUCCESS;
}
/* }}}*/
-static const char hexChars[] = "0123456789ABCDEF";
-
-static int phar_hex_str(const char *digest, size_t digest_len, char ** signature)
-{
- int pos = -1;
- size_t len;
-
- *signature = (char*)safe_emalloc(digest_len, 2, 1);
-
- for(len = 0; len < digest_len; ++len) {
- (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
- (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
- }
- (*signature)[++pos] = '\0';
- return pos;
-}
-
/**
* 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_filename to process the manifest, but can be called
* directly.
*/
-int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
+static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
{
char b32[4], *buffer, *endbuffer, *savebuf;
phar_archive_data *mydata = NULL;
if (pphar) {
*pphar = NULL;
}
+
if (error) {
*error = NULL;
}
}
buffer = b32;
+
if (3 != php_stream_read(fp, buffer, 3)) {
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
}
+
if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
int nextchar;
halt_offset += 3;
if (EOF == (nextchar = php_stream_getc(fp))) {
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
}
+
if ((char) nextchar == '\r') {
/* if we have an \r we require an \n as well */
if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
}
++halt_offset;
}
+
if ((char) nextchar == '\n') {
++halt_offset;
}
}
+
/* make sure we are at the right location to read the manifest */
if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
/* read in manifest */
buffer = b32;
+
if (4 != php_stream_read(fp, buffer, 4)) {
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
}
+
PHAR_GET_32(buffer, manifest_len);
+
if (manifest_len > 1048576 * 100) {
/* prevent serious memory issues by limiting manifest to at most 100 MB in length */
MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
}
+
buffer = (char *)emalloc(manifest_len);
savebuf = buffer;
endbuffer = buffer + manifest_len;
+
if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
}
/* extract the number of entries */
PHAR_GET_32(buffer, manifest_count);
+
if (manifest_count == 0) {
MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
}
/* extract API version, lowest nibble currently unused */
- manifest_ver = (((unsigned char)buffer[0]) << 8)
- + ((unsigned char)buffer[1]);
+ manifest_ver = (((unsigned char)buffer[0]) << 8)
+ + ((unsigned char)buffer[1]);
buffer += 2;
+
if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
efree(savebuf);
php_stream_close(fp);
PHAR_GET_32(buffer, manifest_flags);
manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
-
manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
/* remember whether this entire phar was compressed with gz/bzip2 */
manifest_flags |= compression;
/* The lowest nibble contains the phar wide flags. The compression flags can */
/* be ignored on reading because it is being generated anyways. */
if (manifest_flags & PHAR_HDR_SIGNATURE) {
- unsigned char buf[1024];
- int read_size, len;
char sig_buf[8], *sig_ptr = sig_buf;
off_t read_len;
+ size_t end_of_phar;
if (-1 == php_stream_seek(fp, -8, SEEK_END)
|| (read_len = php_stream_tell(fp)) < 20
- || 8 != php_stream_read(fp, sig_buf, 8)
+ || 8 != php_stream_read(fp, sig_buf, 8)
|| memcmp(sig_buf+4, "GBMB", 4)) {
efree(savebuf);
php_stream_close(fp);
}
return FAILURE;
}
+
PHAR_GET_32(sig_ptr, sig_flags);
+
switch(sig_flags) {
-#if HAVE_HASH_EXT
- case PHAR_SIG_SHA512: {
- unsigned char digest[64], saved[64];
- PHP_SHA512_CTX context;
-
- php_stream_rewind(fp);
- PHP_SHA512Init(&context);
- read_len -= sizeof(digest);
- if (read_len > sizeof(buf)) {
- read_size = sizeof(buf);
- } else {
- read_size = (int)read_len;
- }
- while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
- PHP_SHA512Update(&context, buf, len);
- read_len -= (off_t)len;
- if (read_len < read_size) {
- read_size = (int)read_len;
+ case PHAR_SIG_OPENSSL: {
+ php_uint32 signature_len;
+ char *sig;
+ off_t whence;
+
+ /* we store the signature followed by the signature length */
+ if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
+ || 4 != php_stream_read(fp, sig_buf, 4)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
+ }
+ return FAILURE;
}
- }
- PHP_SHA512Final(digest, &context);
- if (read_len > 0
- || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
- || memcmp(digest, saved, sizeof(digest))) {
- efree(savebuf);
- php_stream_close(fp);
- if (error) {
- spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ sig_ptr = sig_buf;
+ PHAR_GET_32(sig_ptr, signature_len);
+ sig = (char *) emalloc(signature_len);
+ whence = signature_len + 4;
+ whence = -whence;
+
+ if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
+ || !(end_of_phar = php_stream_tell(fp))
+ || signature_len != php_stream_read(fp, sig, signature_len)) {
+ efree(savebuf);
+ efree(sig);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
+ }
+ return FAILURE;
}
- return FAILURE;
- }
- sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
+ if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error TSRMLS_CC)) {
+ efree(savebuf);
+ efree(sig);
+ php_stream_close(fp);
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
+ efree(save);
+ }
+ return FAILURE;
+ }
+ efree(sig);
+ }
break;
- }
- case PHAR_SIG_SHA256: {
- unsigned char digest[32], saved[32];
- PHP_SHA256_CTX context;
+#if HAVE_HASH_EXT
+ case PHAR_SIG_SHA512: {
+ unsigned char digest[64];
- php_stream_rewind(fp);
- PHP_SHA256Init(&context);
- read_len -= sizeof(digest);
- if (read_len > sizeof(buf)) {
- read_size = sizeof(buf);
- } else {
- read_size = (int)read_len;
- }
- while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
- PHP_SHA256Update(&context, buf, len);
- read_len -= (off_t)len;
- if (read_len < read_size) {
- read_size = (int)read_len;
+ php_stream_seek(fp, -(8 + 64), SEEK_END);
+ read_len = php_stream_tell(fp);
+
+ if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
}
- }
- PHP_SHA256Final(digest, &context);
- if (read_len > 0
- || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
- || memcmp(digest, saved, sizeof(digest))) {
- efree(savebuf);
- php_stream_close(fp);
- if (error) {
- spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error TSRMLS_CC)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
+ efree(save);
+ }
+ return FAILURE;
}
- return FAILURE;
+ break;
}
+ case PHAR_SIG_SHA256: {
+ unsigned char digest[32];
- sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
- break;
- }
-#else
- case PHAR_SIG_SHA512:
- case PHAR_SIG_SHA256:
- efree(savebuf);
- php_stream_close(fp);
- if (error) {
- spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
- }
- return FAILURE;
-#endif
- case PHAR_SIG_SHA1: {
- unsigned char digest[20], saved[20];
- PHP_SHA1_CTX context;
-
- php_stream_rewind(fp);
- PHP_SHA1Init(&context);
- read_len -= sizeof(digest);
- if (read_len > sizeof(buf)) {
- read_size = sizeof(buf);
- } else {
- read_size = (int)read_len;
- }
- while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
- PHP_SHA1Update(&context, buf, len);
- read_len -= (off_t)len;
- if (read_len < read_size) {
- read_size = (int)read_len;
+ php_stream_seek(fp, -(8 + 32), SEEK_END);
+ read_len = php_stream_tell(fp);
+
+ if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
}
- }
- PHP_SHA1Final(digest, &context);
- if (read_len > 0
- || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
- || memcmp(digest, saved, sizeof(digest))) {
+ if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error TSRMLS_CC)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
+ efree(save);
+ }
+ return FAILURE;
+ }
+ break;
+ }
+#else
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
efree(savebuf);
php_stream_close(fp);
+
if (error) {
- spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
}
return FAILURE;
- }
+#endif
+ case PHAR_SIG_SHA1: {
+ unsigned char digest[20];
- sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
- break;
- }
- case PHAR_SIG_MD5: {
- unsigned char digest[16], saved[16];
- PHP_MD5_CTX context;
+ php_stream_seek(fp, -(8 + 20), SEEK_END);
+ read_len = php_stream_tell(fp);
- php_stream_rewind(fp);
- PHP_MD5Init(&context);
- read_len -= sizeof(digest);
- if (read_len > sizeof(buf)) {
- read_size = sizeof(buf);
- } else {
- read_size = (int)read_len;
- }
- while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
- PHP_MD5Update(&context, buf, len);
- read_len -= (off_t)len;
- if (read_len < read_size) {
- read_size = (int)read_len;
+ if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
}
+
+ if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error TSRMLS_CC)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
+ efree(save);
+ }
+ return FAILURE;
+ }
+ break;
}
- PHP_MD5Final(digest, &context);
+ case PHAR_SIG_MD5: {
+ unsigned char digest[16];
+
+ php_stream_seek(fp, -(8 + 16), SEEK_END);
+ read_len = php_stream_tell(fp);
+
+ if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
- if (read_len > 0
- || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
- || memcmp(digest, saved, sizeof(digest))) {
+ if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error TSRMLS_CC)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
+ efree(save);
+ }
+ return FAILURE;
+ }
+ break;
+ }
+ default:
efree(savebuf);
php_stream_close(fp);
+
if (error) {
- spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
}
return FAILURE;
- }
-
- sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
- break;
- }
- default:
- efree(savebuf);
- php_stream_close(fp);
- if (error) {
- spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
- }
- return FAILURE;
}
} else if (PHAR_G(require_hash)) {
efree(savebuf);
php_stream_close(fp);
+
if (error) {
spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
}
/* extract alias */
PHAR_GET_32(buffer, tmp_len);
+
if (buffer + tmp_len > endbuffer) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
}
+
if (manifest_len < 10 + tmp_len) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
}
+
/* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
if (tmp_len) {
/* if the alias is stored we enforce it (implicit overrides explicit) */
{
buffer[tmp_len] = '\0';
php_stream_close(fp);
+
if (signature) {
efree(signature);
}
+
if (error) {
spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
}
+
efree(savebuf);
return FAILURE;
}
+
alias_len = tmp_len;
alias = buffer;
buffer += tmp_len;
MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
}
- mydata = ecalloc(sizeof(phar_archive_data), 1);
+ mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
+ mydata->is_persistent = PHAR_G(persist);
/* check whether we have meta data, zero check works regardless of byte order */
- if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
- MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+ if (mydata->is_persistent) {
+ char *mysave = buffer;
+ PHAR_GET_32(buffer, mydata->metadata_len);
+ buffer = mysave;
+ if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) {
+ MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+ }
+ } else {
+ if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
+ MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+ }
}
/* set up our manifest */
- 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, manifest_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, manifest_count * 2,
+ zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
+ mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(mydata->fname, fname_len);
+#endif
+ mydata->fname_len = fname_len;
offset = halt_offset + manifest_len + 4;
memset(&entry, 0, sizeof(phar_entry_info));
entry.phar = mydata;
entry.fp_type = PHAR_FP;
+ entry.is_persistent = mydata->is_persistent;
for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
if (buffer + 4 > endbuffer) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
}
+
PHAR_GET_32(buffer, entry.filename_len);
+
if (entry.filename_len == 0) {
MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
}
+
+ if (entry.is_persistent) {
+ entry.manifest_pos = manifest_index;
+ }
+
if (buffer + entry.filename_len + 20 > endbuffer) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
}
+
if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
entry.is_dir = 1;
} else {
entry.is_dir = 0;
}
- entry.filename = estrndup(buffer, entry.filename_len);
+
+ phar_add_virtual_dirs(mydata, buffer, entry.filename_len TSRMLS_CC);
+ entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
buffer += entry.filename_len;
PHAR_GET_32(buffer, entry.uncompressed_filesize);
PHAR_GET_32(buffer, entry.timestamp);
+
if (offset == halt_offset + (int)manifest_len + 4) {
mydata->min_timestamp = entry.timestamp;
mydata->max_timestamp = entry.timestamp;
mydata->max_timestamp = entry.timestamp;
}
}
+
PHAR_GET_32(buffer, entry.compressed_filesize);
PHAR_GET_32(buffer, entry.crc32);
PHAR_GET_32(buffer, entry.flags);
+
if (entry.is_dir) {
entry.filename_len--;
entry.flags |= PHAR_ENT_PERM_DEF_DIR;
}
- if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
- efree(entry.filename);
- MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
+
+ if (entry.is_persistent) {
+ if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
+ pefree(entry.filename, entry.is_persistent);
+ MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
+ }
+ } else {
+ if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
+ pefree(entry.filename, entry.is_persistent);
+ MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
+ }
}
+
entry.offset = entry.offset_abs = offset;
offset += entry.compressed_filesize;
+
switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
- case PHAR_ENT_COMPRESSED_GZ:
- if (!PHAR_G(has_zlib)) {
- if (entry.metadata) {
- zval_ptr_dtor(&entry.metadata);
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (!PHAR_G(has_zlib)) {
+ if (entry.metadata) {
+ if (entry.is_persistent) {
+ free(entry.metadata);
+ } else {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ }
+ pefree(entry.filename, entry.is_persistent);
+ MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
}
- efree(entry.filename);
- MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
- }
- break;
- case PHAR_ENT_COMPRESSED_BZ2:
- if (!PHAR_G(has_bz2)) {
- if (entry.metadata) {
- zval_ptr_dtor(&entry.metadata);
+ break;
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (!PHAR_G(has_bz2)) {
+ if (entry.metadata) {
+ if (entry.is_persistent) {
+ free(entry.metadata);
+ } else {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ }
+ pefree(entry.filename, entry.is_persistent);
+ MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
}
- efree(entry.filename);
- MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
- }
- break;
- default:
- if (entry.uncompressed_filesize != entry.compressed_filesize) {
- if (entry.metadata) {
- zval_ptr_dtor(&entry.metadata);
+ break;
+ default:
+ if (entry.uncompressed_filesize != entry.compressed_filesize) {
+ if (entry.metadata) {
+ if (entry.is_persistent) {
+ free(entry.metadata);
+ } else {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ }
+ pefree(entry.filename, entry.is_persistent);
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
}
- efree(entry.filename);
- MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
- }
- break;
+ break;
}
+
manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
/* if signature matched, no need to check CRC32 for each file */
entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
+ phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
}
mydata->internal_file_start = halt_offset + manifest_len + 4;
mydata->halt_offset = halt_offset;
mydata->flags = manifest_flags;
- mydata->fp = fp;
- mydata->fname = estrndup(fname, fname_len);
-#ifdef PHP_WIN32
- phar_unixify_path_separators(mydata->fname, fname_len);
-#endif
- mydata->fname_len = fname_len;
endbuffer = strrchr(mydata->fname, '/');
+
if (endbuffer) {
mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
if (mydata->ext == endbuffer) {
mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
}
}
- mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
+
+ mydata->alias = alias ?
+ pestrndup(alias, alias_len, mydata->is_persistent) :
+ pestrndup(mydata->fname, fname_len, mydata->is_persistent);
mydata->alias_len = alias ? alias_len : fname_len;
mydata->sig_flags = sig_flags;
+ mydata->fp = fp;
mydata->sig_len = sig_len;
mydata->signature = signature;
phar_request_initialize(TSRMLS_C);
+
if (register_alias) {
phar_archive_data **fd_ptr;
mydata->is_temporary_alias = temp_alias;
+
if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
signature = NULL;
fp = NULL;
MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
}
+
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
signature = NULL;
MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
}
}
+
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
} else {
mydata->is_temporary_alias = 1;
}
+
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
efree(savebuf);
-
+
if (pphar) {
*pphar = mydata;
}
phar_archive_data **test, *unused = NULL;
test = &unused;
+
if (error) {
*error = NULL;
}
/* first try to open an existing file */
- if (phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
+ if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
goto check_file;
}
+
/* next try to create a new file */
- if (FAILURE == phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
+ if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
if (error) {
spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised", fname);
}
return FAILURE;
}
-
check_file:
if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
if (pphar) {
*pphar = *test;
}
+
if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
if (error) {
spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
}
return FAILURE;
}
+
if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
phar_entry_info *stub;
if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
return FAILURE;
}
}
+
if (!PHAR_G(readonly) || (*test)->is_data) {
(*test)->is_writeable = 1;
}
}
return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
-
}
+/* }}} */
int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
{
return FAILURE;
}
#endif
-
if (php_check_open_basedir(fname TSRMLS_CC)) {
return FAILURE;
}
/* first open readonly so it won't be created if not present */
fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
+
if (actual) {
fname = actual;
fname_len = strlen(actual);
return FAILURE;
}
}
+
if (actual) {
efree(actual);
}
}
/* set up our manifest */
- mydata = ecalloc(sizeof(phar_archive_data), 1);
-
+ mydata = ecalloc(1, sizeof(phar_archive_data));
mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
fname_len = strlen(mydata->fname);
#ifdef PHP_WIN32
phar_unixify_path_separators(mydata->fname, fname_len);
#endif
p = strrchr(mydata->fname, '/');
+
if (p) {
mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
if (mydata->ext == p) {
if (pphar) {
*pphar = mydata;
}
+
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->virtual_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
mydata->fname_len = fname_len;
snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
mydata->is_temporary_alias = alias ? 0 : 1;
mydata->is_brandnew = 1;
phar_request_initialize(TSRMLS_C);
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+
if (is_data) {
alias = NULL;
alias_len = 0;
if (error) {
spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
}
+
zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+
if (pphar) {
*pphar = NULL;
}
+
return FAILURE;
}
}
+
mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
mydata->alias_len = alias ? alias_len : fname_len;
}
+
if (alias_len && alias) {
if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
if (options & REPORT_ERRORS) {
spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
}
}
+
zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+
if (pphar) {
*pphar = NULL;
}
+
return FAILURE;
}
}
+
return SUCCESS;
}
/* }}}*/
} else if (error && *error) {
return FAILURE;
}
-
#if PHP_MAJOR_VERSION < 6
if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
return FAILURE;
}
#endif
-
if (php_check_open_basedir(fname TSRMLS_CC)) {
return FAILURE;
}
fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
+
if (!fp) {
if (options & REPORT_ERRORS) {
if (error) {
}
ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
+
if (actual) {
efree(actual);
}
+
return ret;
}
/* }}}*/
-static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len)
+static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
{
const char *c;
int so_far = 0;
- /* this assumes buf_len > search_len */
+ if (buf_len < search_len) {
+ return NULL;
+ }
+
c = buf - 1;
+
do {
if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
return (char *) NULL;
}
+
so_far = c - buf;
+
if (so_far >= (buf_len - search_len)) {
return (char *) NULL;
}
+
if (!memcmp(c, search, search_len)) {
return (char *) c;
}
} while (1);
}
+/* }}} */
/**
* Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
if (error) {
*error = NULL;
}
+
if (-1 == php_stream_rewind(fp)) {
MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
}
if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
}
+
if (!test) {
test = '\1';
pos = buffer+tokenlen;
MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
}
array_init(&filterparams);
-
/* this is defined in zlib's zconf.h */
#ifndef MAX_WBITS
#define MAX_WBITS 15
#endif
add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
+
/* entire file is gzip-compressed, uncompress to temporary file */
if (!(temp = php_stream_fopen_tmpfile())) {
MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
}
+
php_stream_rewind(fp);
filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
+
if (!filter) {
err = 1;
add_assoc_long(&filterparams, "window", MAX_WBITS);
filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
zval_dtor(&filterparams);
+
if (!filter) {
php_stream_close(temp);
MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
} else {
zval_dtor(&filterparams);
}
+
php_stream_filter_append(&temp->writefilters, filter);
+
if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
if (err) {
php_stream_close(temp);
php_stream_close(temp);
MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
}
+
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
php_stream_close(fp);
if (!PHAR_G(has_bz2)) {
MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
}
+
/* entire file is bzip-compressed, uncompress to temporary file */
if (!(temp = php_stream_fopen_tmpfile())) {
MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
}
+
php_stream_rewind(fp);
filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+
if (!filter) {
php_stream_close(temp);
MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
}
+
php_stream_filter_append(&temp->writefilters, filter);
+
if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
php_stream_close(temp);
MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
}
+
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
php_stream_close(fp);
test = '\0';
continue;
}
+
if (!memcmp(pos, zip_magic, 4)) {
php_stream_seek(fp, 0, SEEK_END);
return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
}
+
if (got > 512) {
if (phar_is_tar(pos, fname)) {
php_stream_rewind(fp);
}
}
}
- if ((pos = phar_strnstr(buffer, 1024 + sizeof(token), token, sizeof(token)-1)) != NULL) {
+
+ if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
}
halt_offset += got;
memmove(buffer, buffer + tokenlen, got + 1);
}
-
+
MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
}
/* }}} */
* if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
* succeed if we are creating the file, otherwise fail.
*/
-static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC)
+static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC) /* {{{ */
{
php_stream_statbuf ssb;
char *realpath, old, *a = (char *)(ext + ext_len);
old = *a;
*a = '\0';
+
if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
#ifdef PHP_WIN32
phar_unixify_path_separators(realpath, strlen(realpath));
efree(realpath);
return SUCCESS;
}
+
+ if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
+ *a = old;
+ efree(realpath);
+ return SUCCESS;
+ }
efree(realpath);
}
+
if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) {
*a = old;
+
if (ssb.sb.st_mode & S_IFDIR) {
return FAILURE;
}
+
if (for_create == 1) {
return FAILURE;
}
+
return SUCCESS;
} else {
char *slash;
*a = old;
return FAILURE;
}
+
slash = (char *) strrchr(fname, '/');
*a = old;
+
if (slash) {
old = *slash;
*slash = '\0';
}
+
if (SUCCESS != php_stream_stat_path((char *) fname, &ssb)) {
if (slash) {
*slash = old;
a = strstr(realpath, fname) + ((ext - fname) + ext_len);
*a = '\0';
slash = strrchr(realpath, '/');
+
if (slash) {
*slash = '\0';
} else {
efree(realpath);
return FAILURE;
}
+
if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
efree(realpath);
return FAILURE;
}
+
efree(realpath);
+
if (ssb.sb.st_mode & S_IFDIR) {
return SUCCESS;
}
}
+
return FAILURE;
}
+
if (slash) {
*slash = old;
}
+
if (ssb.sb.st_mode & S_IFDIR) {
return SUCCESS;
}
+
return FAILURE;
}
}
+/* }}} */
/* check for ".phar" in extension */
-static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC)
+static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC) /* {{{ */
{
char test[51];
const char *pos;
if (ext_len >= 50) {
return FAILURE;
}
+
if (executable == 1) {
/* copy "." as well */
memcpy(test, ext_str - 1, ext_len + 1);
/* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
/* (phar://hi/there/.phar/oops is also invalid) */
pos = strstr(test, ".phar");
+
if (pos && (*(pos - 1) != '/')
&& (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
return FAILURE;
}
}
+
/* data phars need only contain a single non-"." to be valid */
if (!executable) {
pos = strstr(ext_str, ".phar");
return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
}
}
+
return FAILURE;
}
+/* }}} */
/*
* if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
* the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
* extension rules, not to iterate.
*/
-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) /* {{{ */
{
const char *pos, *slash;
- int filename_len = strlen(filename);
*ext_str = NULL;
if (!filename_len || filename_len == 1) {
return FAILURE;
}
+
phar_request_initialize(TSRMLS_C);
/* first check for alias in first segment */
- pos = strchr(filename, '/');
+ pos = memchr(filename, '/', filename_len);
+
if (pos && pos != filename) {
if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
*ext_str = pos;
*ext_len = -1;
return FAILURE;
}
+
+ if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
+ *ext_str = pos;
+ *ext_len = -1;
+ return FAILURE;
+ }
}
- if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
phar_archive_data **pphar;
if (is_complete) {
*ext_str = filename + (filename_len - (*pphar)->ext_len);
woohoo:
*ext_len = (*pphar)->ext_len;
+
if (executable == 2) {
return SUCCESS;
}
+
if (executable == 1 && !(*pphar)->is_data) {
return SUCCESS;
}
+
if (!executable && (*pphar)->is_data) {
return SUCCESS;
}
+
return FAILURE;
}
+
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
+ *ext_str = filename + (filename_len - (*pphar)->ext_len);
+ goto woohoo;
+ }
} else {
phar_zstr key;
char *str_key;
ulong unused;
zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
+
while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) {
if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) {
break;
zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
continue;
}
+
if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
|| filename[keylen] == '/' || filename[keylen] == '\0')) {
if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
*ext_str = filename + (keylen - (*pphar)->ext_len);
goto woohoo;
}
+
zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
}
+
+ if (PHAR_G(manifest_cached)) {
+ zend_hash_internal_pointer_reset(&cached_phars);
+
+ while (FAILURE != zend_hash_has_more_elements(&cached_phars)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&cached_phars, &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+
+ PHAR_STR(key, str_key);
+
+ if (keylen > (uint) filename_len) {
+ zend_hash_move_forward(&cached_phars);
+ continue;
+ }
+
+ if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
+ || filename[keylen] == '/' || filename[keylen] == '\0')) {
+ if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
+ break;
+ }
+ *ext_str = filename + (keylen - (*pphar)->ext_len);
+ goto woohoo;
+ }
+ zend_hash_move_forward(&cached_phars);
+ }
+ }
}
}
- pos = strchr(filename + 1, '.');
+ pos = memchr(filename + 1, '.', filename_len);
next_extension:
if (!pos) {
return FAILURE;
}
+
while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
- pos = strchr(pos + 1, '.');
+ pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1);
if (!pos) {
return FAILURE;
}
}
- slash = strchr(pos, '/');
+ slash = memchr(pos, '/', filename_len - (pos - filename));
+
if (!slash) {
/* this is a url like "phar://blah.phar" with no directory */
*ext_str = pos;
*ext_len = strlen(pos);
+
/* file extension must contain "phar" */
switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
- case SUCCESS :
+ case SUCCESS:
return SUCCESS;
- case FAILURE :
+ case FAILURE:
/* we are at the end of the string, so we fail */
return FAILURE;
}
}
+
/* we've found an extension that ends at a directory separator */
*ext_str = pos;
*ext_len = slash - pos;
+
switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
- case SUCCESS :
+ case SUCCESS:
return SUCCESS;
- case FAILURE :
+ case FAILURE:
/* look for more extensions */
pos = strchr(pos + 1, '.');
if (pos) {
}
goto next_extension;
}
+
return FAILURE;
}
/* }}} */
-static int php_check_dots(const char *element, int n)
+static int php_check_dots(const char *element, int n) /* {{{ */
{
for(n--; n >= 0; --n) {
if (element[n] != '.') {
}
return 0;
}
+/* }}} */
#define IS_DIRECTORY_UP(element, len) \
(len >= 2 && !php_check_dots(element, len))
#define IS_DIRECTORY_CURRENT(element, len) \
(len == 1 && element[0] == '.')
-#define IS_BACKSLASH(c) ((c) == '/')
+#define IS_BACKSLASH(c) ((c) == '/')
#ifdef COMPILE_DL_PHAR
/* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */
-static inline int in_character_class(char ch, const char *delim)
+static inline int in_character_class(char ch, const char *delim) /* {{{ */
{
while (*delim) {
if (*delim == ch) {
}
return 0;
}
+/* }}} */
-char *tsrm_strtok_r(char *s, const char *delim, char **last)
+char *tsrm_strtok_r(char *s, const char *delim, char **last) /* {{{ */
{
char *token;
while (*s && in_character_class(*s, delim)) {
++s;
}
+
if (!*s) {
return NULL;
}
while (*s && !in_character_class(*s, delim)) {
++s;
}
+
if (!*s) {
*last = s;
} else {
*s = '\0';
*last = s + 1;
}
+
return token;
}
+/* }}} */
#endif
/**
*/
char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
{
- char *ptr, *free_path, *new_phar;
+ char newpath[MAXPATHLEN];
+ int newpath_len;
+ char *ptr;
char *tok;
- int ptr_length, new_phar_len = 1, path_length = *new_len;
+ int ptr_length, path_length = *new_len;
if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
- free_path = path;
- new_phar_len = PHAR_G(cwd_len);
- new_phar = estrndup(PHAR_G(cwd), new_phar_len);
+ newpath_len = PHAR_G(cwd_len);
+ memcpy(newpath, PHAR_G(cwd), newpath_len);
} else {
- free_path = path;
- new_phar = estrndup("/\0", 2);
+ newpath[0] = '/';
+ newpath_len = 1;
}
- tok = NULL;
- ptr = tsrm_strtok_r(path, "/", &tok);
- while (ptr) {
- ptr_length = strlen(ptr);
- if (IS_DIRECTORY_UP(ptr, ptr_length)) {
- char save;
+ ptr = path;
+
+ if (*ptr == '/') {
+ ++ptr;
+ }
+
+ tok = ptr;
- save = '/';
+ do {
+ ptr = memchr(ptr, '/', path_length - (ptr - path));
+ } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
+
+ if (!ptr && (path_length - (tok - path))) {
+ switch (path_length - (tok - path)) {
+ case 1:
+ if (*tok == '.') {
+ efree(path);
+ *new_len = 1;
+ return estrndup("/", 1);
+ }
+ break;
+ case 2:
+ if (tok[0] == '.' && tok[1] == '.') {
+ efree(path);
+ *new_len = 1;
+ return estrndup("/", 1);
+ }
+ }
+ return path;
+ }
-#define PREVIOUS new_phar[new_phar_len - 1]
+ while (ptr) {
+ ptr_length = ptr - tok;
+last_time:
+ if (IS_DIRECTORY_UP(tok, ptr_length)) {
+#define PREVIOUS newpath[newpath_len - 1]
- while (new_phar_len > 1 &&
- !IS_BACKSLASH(PREVIOUS)) {
- save = PREVIOUS;
- PREVIOUS = '\0';
- new_phar_len--;
+ while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
+ newpath_len--;
}
- if (new_phar[0] != '/') {
- new_phar[new_phar_len++] = save;
- new_phar[new_phar_len] = '\0';
- } else if (new_phar_len > 1) {
- PREVIOUS = '\0';
- new_phar_len--;
+ if (newpath[0] != '/') {
+ newpath[newpath_len] = '\0';
+ } else if (newpath_len > 1) {
+ --newpath_len;
}
- } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) {
- if (new_phar_len > 1) {
- new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1+1);
- new_phar[new_phar_len++] = '/';
- memcpy(&new_phar[new_phar_len], ptr, ptr_length+1);
+ } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
+ if (newpath_len > 1) {
+ newpath[newpath_len++] = '/';
+ memcpy(newpath + newpath_len, tok, ptr_length+1);
} else {
- new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1);
- memcpy(&new_phar[new_phar_len], ptr, ptr_length+1);
+ memcpy(newpath + newpath_len, tok, ptr_length+1);
}
- new_phar_len += ptr_length;
+ newpath_len += ptr_length;
}
- ptr = tsrm_strtok_r(NULL, "/", &tok);
- }
- if (path[path_length-1] == '/' && new_phar_len > 1) {
- new_phar = (char*)erealloc(new_phar, new_phar_len + 2);
- new_phar[new_phar_len++] = '/';
- new_phar[new_phar_len] = 0;
- }
+ if (ptr == path + path_length) {
+ break;
+ }
- efree(free_path);
+ tok = ++ptr;
- if (new_phar_len == 0) {
- new_phar = (char *) erealloc(new_phar, new_phar_len+1+1);
- new_phar[new_phar_len] = '/';
- new_phar[++new_phar_len] = '\0';
+ do {
+ ptr = memchr(ptr, '/', path_length - (ptr - path));
+ } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
+
+ if (!ptr && (path_length - (tok - path))) {
+ ptr_length = path_length - (tok - path);
+ ptr = path + path_length;
+ goto last_time;
+ }
}
- *new_len = new_phar_len;
- return new_phar;
+
+ efree(path);
+ *new_len = newpath_len;
+ return estrndup(newpath, newpath_len);
}
/* }}} */
filename = estrndup(filename, filename_len);
phar_unixify_path_separators(filename, filename_len);
#endif
- if (phar_detect_phar_fname_ext(filename, 0, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
+ if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
if (ext_len != -1) {
if (!ext_str) {
/* no / detected, restore arch for error message */
*arch = filename;
#endif
}
+
if (free_filename) {
efree(filename);
}
+
return FAILURE;
}
+
ext_len = 0;
/* no extension detected - instead we are dealing with an alias */
}
*arch_len = ext_str - filename + ext_len;
*arch = estrndup(filename, *arch_len);
+
if (ext_str[ext_len]) {
*entry_len = filename_len - *arch_len;
*entry = estrndup(ext_str+ext_len, *entry_len);
*entry_len = 1;
*entry = estrndup("/", 1);
}
+
if (free_filename) {
efree(filename);
}
+
return SUCCESS;
}
/* }}} */
if (error) {
*error = NULL;
}
+
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
}
MAKE_STD_ZVAL(halt_constant);
+
if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
FREE_ZVAL(halt_constant);
if (error) {
}
return FAILURE;
}
+
halt_offset = Z_LVAL(*halt_constant);
FREE_ZVAL(halt_constant);
-
#if PHP_MAJOR_VERSION < 6
if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
- return FAILURE;
- }
+ return FAILURE;
+ }
#endif
if (php_check_open_basedir(fname TSRMLS_CC)) {
return FAILURE;
- }
+ }
fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
+
if (!fp) {
- if (error) {
+ if (error) {
spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
- }
+ }
if (actual) {
- efree(actual);
- }
+ efree(actual);
+ }
return FAILURE;
- }
+ }
if (actual) {
- fname = actual;
+ fname = actual;
fname_len = strlen(actual);
- }
+ }
ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, error TSRMLS_CC);
- if (actual) {
+
+ if (actual) {
efree(actual);
- }
- return ret;
+ }
+
+ return ret;
}
/* }}} */
if (error) {
*error = NULL;
}
+
if (entry->is_zip) {
/* verify local file header */
phar_zip_file_header local;
spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
return FAILURE;
}
- php_stream_seek(idata->phar->fp, entry->header_offset, SEEK_SET);
+ php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
- if (sizeof(local) != php_stream_read(idata->phar->fp, (char *) &local, sizeof(local))) {
+ if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
return FAILURE;
}
+
/* verify local header */
if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local head of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
return FAILURE;
}
+
/* construct actual offset to file start - local extra_len can be different from central extra_len */
entry->offset = entry->offset_abs =
sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
+
if (idata->zero && idata->zero != entry->offset_abs) {
idata->zero = entry->offset_abs;
}
}
- php_stream_seek(fp, idata->zero, SEEK_SET);
+
+ php_stream_seek(fp, idata->zero, SEEK_SET);
+
while (len--) {
CRC32(crc, php_stream_getc(fp));
}
+
php_stream_seek(fp, idata->zero, SEEK_SET);
+
if (~crc == crc32) {
entry->is_crc_checked = 1;
return SUCCESS;
#include "stub.h"
-char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC)
+char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) /* {{{ */
{
char *stub = NULL;
int index_len, web_len;
phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
return stub;
}
+/* }}} */
+
+#ifndef PHAR_HAVE_OPENSSL
+static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
+
+ MAKE_STD_ZVAL(zdata);
+ MAKE_STD_ZVAL(openssl);
+ ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
+ MAKE_STD_ZVAL(zsig);
+ ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
+ MAKE_STD_ZVAL(zkey);
+ ZVAL_STRINGL(zkey, key, key_len, 1);
+ zp[0] = &zdata;
+ zp[1] = &zsig;
+ zp[2] = &zkey;
+
+ php_stream_rewind(fp);
+ Z_TYPE_P(zdata) = IS_STRING;
+ Z_STRLEN_P(zdata) = end;
+ if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ return FAILURE;
+ }
+
+#if PHP_VERSION_ID < 50300
+ if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
+#else
+ if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
+#endif
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ zval_dtor(openssl);
+ return FAILURE;
+ }
+
+ zval_dtor(openssl);
+ efree(openssl);
+
+ fci.param_count = 3;
+ fci.params = zp;
+#if PHP_VERSION_ID < 50300
+ ++(zdata->refcount);
+ ++(zsig->refcount);
+ ++(zkey->refcount);
+#else
+ Z_ADDREF_P(zdata);
+
+ if (is_sign) {
+ Z_SET_ISREF_P(zsig);
+ } else {
+ Z_ADDREF_P(zsig);
+ }
+
+ Z_ADDREF_P(zkey);
+#endif
+ fci.retval_ptr_ptr = &retval_ptr;
+
+ if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ efree(zdata);
+ efree(zkey);
+ efree(zsig);
+ return FAILURE;
+ }
+#if PHP_VERSION_ID < 50300
+ --(zdata->refcount);
+ --(zsig->refcount);
+ --(zkey->refcount);
+#else
+ Z_DELREF_P(zdata);
+
+ if (is_sign) {
+ Z_UNSET_ISREF_P(zsig);
+ } else {
+ Z_DELREF_P(zsig);
+ }
+
+ Z_DELREF_P(zkey);
+#endif
+ zval_dtor(zdata);
+ efree(zdata);
+ zval_dtor(zkey);
+ efree(zkey);
+
+ switch (Z_TYPE_P(retval_ptr)) {
+ default:
+ case IS_LONG:
+ zval_dtor(zsig);
+ efree(zsig);
+ if (1 == Z_LVAL_P(retval_ptr)) {
+ efree(retval_ptr);
+ return SUCCESS;
+ }
+ efree(retval_ptr);
+ return FAILURE;
+ case IS_BOOL:
+ efree(retval_ptr);
+ if (Z_BVAL_P(retval_ptr)) {
+ *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
+ *signature_len = Z_STRLEN_P(zsig);
+ zval_dtor(zsig);
+ efree(zsig);
+ return SUCCESS;
+ }
+ zval_dtor(zsig);
+ efree(zsig);
+ return FAILURE;
+ }
+}
+/* }}} */
+#endif /* #ifndef PHAR_HAVE_OPENSSL */
/**
* Save phar contents to disk
smart_str main_metadata_str = {0};
int free_user_stub, free_fp = 1, free_ufp = 1;
- if (error) {
- *error = NULL;
+ 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_G(readonly) && !phar->is_data) {
- return EOF;
+ if (error) {
+ *error = NULL;
}
if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
if (phar->is_zip) {
return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
}
+
if (phar->is_tar) {
return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
}
+ if (PHAR_G(readonly)) {
+ return EOF;
+ }
+
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
}
len = pos - user_stub + 18;
if ((size_t)len != php_stream_write(newfile, user_stub, len)
- || 5 != php_stream_write(newfile, " ?>\r\n", 5)) {
+ || 5 != php_stream_write(newfile, " ?>\r\n", 5)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
new_manifest_count = 0;
offset = 0;
for (zend_hash_internal_pointer_reset(&phar->manifest);
- zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
- zend_hash_move_forward(&phar->manifest)) {
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
/* write the manifest header */
if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
|| (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
+
if (closeoldfile) {
php_stream_close(oldfile);
}
+
php_stream_close(newfile);
phar->alias_len = restore_alias_len;
+
if (error) {
spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
}
+
return EOF;
}
-
+
phar->alias_len = restore_alias_len;
-
+
phar_set_32(manifest, main_metadata_str.len);
if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
&& main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
smart_str_free(&main_metadata_str);
+
if (closeoldfile) {
php_stream_close(oldfile);
}
+
php_stream_close(newfile);
phar->alias_len = restore_alias_len;
+
if (error) {
spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
}
+
return EOF;
- }
+ }
smart_str_free(&main_metadata_str);
-
+
/* re-calculate the manifest location to simplify later code */
manifest_ftell = php_stream_tell(newfile);
-
+
/* now write the manifest */
for (zend_hash_internal_pointer_reset(&phar->manifest);
- zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
- zend_hash_move_forward(&phar->manifest)) {
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+
if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
+
if (entry->is_deleted || entry->is_mounted) {
/* remove this from the new phar if deleted, ignore if mounted */
continue;
}
+
if (entry->is_dir) {
/* add 1 for trailing slash */
phar_set_32(entry_buffer, entry->filename_len + 1);
} else {
phar_set_32(entry_buffer, entry->filename_len);
}
+
if (4 != php_stream_write(newfile, entry_buffer, 4)
|| entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
|| (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
}
return EOF;
}
+
/* set the manifest meta-data:
4: uncompressed filesize
4: creation timestamp
phar_set_32(entry_buffer+12, entry->crc32);
phar_set_32(entry_buffer+16, entry->flags);
phar_set_32(entry_buffer+20, entry->metadata_str.len);
+
if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
|| entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
+
php_stream_close(newfile);
+
if (error) {
spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
+
return EOF;
}
}
-
+
/* now copy the actual file data to the new phar */
offset = php_stream_tell(newfile);
for (zend_hash_internal_pointer_reset(&phar->manifest);
- zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
- zend_hash_move_forward(&phar->manifest)) {
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+
if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
+
if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
continue;
}
+
if (entry->cfp) {
file = entry->cfp;
php_stream_rewind(file);
return EOF;
}
}
+
if (!file) {
if (closeoldfile) {
php_stream_close(oldfile);
}
return EOF;
}
- /* this will have changed for all files that have either
- changed compression or been modified */
+
+ /* this will have changed for all files that have either changed compression or been modified */
entry->offset = entry->offset_abs = offset;
offset += entry->compressed_filesize;
wrote = php_stream_copy_to_stream(file, newfile, entry->compressed_filesize);
+
if (entry->compressed_filesize != wrote) {
if (closeoldfile) {
php_stream_close(oldfile);
}
+
php_stream_close(newfile);
+
if (error) {
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
}
+
return EOF;
}
+
entry->is_modified = 0;
+
if (entry->cfp) {
php_stream_close(entry->cfp);
entry->cfp = NULL;
}
+
if (entry->fp_type == PHAR_MOD) {
- /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed
- when the phar_entry_data is phar_entry_delref'ed */
+ /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
php_stream_close(entry->fp);
}
+
entry->fp = NULL;
entry->fp_type = PHAR_FP;
} else if (entry->fp_type == PHAR_UFP) {
/* append signature */
if (global_flags & PHAR_HDR_SIGNATURE) {
- unsigned char buf[1024];
- int sig_flags = 0, sig_len;
char sig_buf[4];
php_stream_rewind(newfile);
-
+
if (phar->signature) {
efree(phar->signature);
+ phar->signature = NULL;
}
-
- switch(phar->sig_flags) {
-#if HAVE_HASH_EXT
- case PHAR_SIG_SHA512: {
- unsigned char digest[64];
- PHP_SHA512_CTX context;
-
- PHP_SHA512Init(&context);
- while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
- PHP_SHA512Update(&context, buf, sig_len);
- }
- PHP_SHA512Final(digest, &context);
- php_stream_write(newfile, (char *) digest, sizeof(digest));
- sig_flags |= PHAR_SIG_SHA512;
- phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
- break;
- }
- case PHAR_SIG_SHA256: {
- unsigned char digest[32];
- PHP_SHA256_CTX context;
- PHP_SHA256Init(&context);
- while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
- PHP_SHA256Update(&context, buf, sig_len);
- }
- PHP_SHA256Final(digest, &context);
- php_stream_write(newfile, (char *) digest, sizeof(digest));
- sig_flags |= PHAR_SIG_SHA256;
- phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
- break;
- }
-#else
- case PHAR_SIG_SHA512:
- case PHAR_SIG_SHA256:
- if (closeoldfile) {
- php_stream_close(oldfile);
- }
- php_stream_close(newfile);
- if (error) {
- spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
- }
- return EOF;
+ switch(phar->sig_flags) {
+#if !HAVE_HASH_EXT
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
+ }
+ return EOF;
#endif
- case PHAR_SIG_PGP:
- /* TODO: currently fall back to sha1,later do both */
- default:
- case PHAR_SIG_SHA1: {
- unsigned char digest[20];
- PHP_SHA1_CTX context;
-
- PHP_SHA1Init(&context);
- while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
- PHP_SHA1Update(&context, buf, sig_len);
- }
- PHP_SHA1Final(digest, &context);
- php_stream_write(newfile, (char *) digest, sizeof(digest));
- sig_flags |= PHAR_SIG_SHA1;
- phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
- break;
- }
- case PHAR_SIG_MD5: {
- unsigned char digest[16];
- PHP_MD5_CTX context;
+ default: {
+ char *digest;
+ int digest_len;
- PHP_MD5Init(&context);
- while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
- PHP_MD5Update(&context, buf, sig_len);
+ if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
+ if (error) {
+ char *save = *error;
+ spprintf(error, 0, "phar error: unable to write signature: %s", save);
+ efree(save);
+ }
+ efree(digest);
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ return EOF;
+ }
+
+ php_stream_write(newfile, digest, digest_len);
+ efree(digest);
+ if (phar->sig_flags == PHAR_SIG_OPENSSL) {
+ phar_set_32(sig_buf, digest_len);
+ php_stream_write(newfile, sig_buf, 4);
+ }
+ break;
}
- PHP_MD5Final(digest, &context);
- php_stream_write(newfile, (char *) digest, sizeof(digest));
- sig_flags |= PHAR_SIG_MD5;
- phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
- break;
- }
}
- phar_set_32(sig_buf, sig_flags);
+ phar_set_32(sig_buf, phar->sig_flags);
php_stream_write(newfile, sig_buf, 4);
php_stream_write(newfile, "GBMB", 4);
- phar->sig_flags = sig_flags;
}
/* finally, close the temp file, rename the original phar,
if (phar->fp && free_fp) {
php_stream_close(phar->fp);
}
+
if (phar->ufp) {
if (free_ufp) {
php_stream_close(phar->ufp);
}
phar->ufp = NULL;
}
+
if (closeoldfile) {
php_stream_close(oldfile);
}
}
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 */
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) {
if (error) {
spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
}
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);
* Every user visible function must have an entry in phar_functions[].
*/
function_entry phar_functions[] = {
- {NULL, NULL, NULL} /* Must be the last line in phar_functions[] */
+ {NULL, NULL, NULL} /* Must be the last line in phar_functions[] */
};
/* }}}*/
}
/* }}} */
-#if PHP_VERSION_ID >= 50300
static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
{
- return php_stream_read(((phar_archive_data*)handle)->fp, buf, len);
+ return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
}
/* }}} */
+#if PHP_VERSION_ID >= 50300
static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
{
return ((phar_archive_data*)handle)->halt_offset + 32;
#else /* PHP_VERSION_ID */
-static long stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
+static long phar_stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
{
- return (long)php_stream_tell((php_stream*)handle);
+ return (long)php_stream_tell(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC));
}
/* }}} */
#endif
/* compressed phar */
#if PHP_VERSION_ID >= 50300
file_handle->type = ZEND_HANDLE_STREAM;
- file_handle->free_filename = 0;
+ /* we do our own reading directly from the phar, don't change the next line */
file_handle->handle.stream.handle = phar;
file_handle->handle.stream.reader = phar_zend_stream_reader;
file_handle->handle.stream.closer = NULL;
file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
file_handle->handle.stream.isatty = 0;
- php_stream_rewind(phar->fp);
+ phar->is_persistent ?
+ php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
+ php_stream_rewind(phar->fp);
memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
#else /* PHP_VERSION_ID */
file_handle->type = ZEND_HANDLE_STREAM;
- file_handle->free_filename = 0;
- file_handle->handle.stream.handle = phar->fp;
- file_handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
+ /* we do our own reading directly from the phar, don't change the next line */
+ file_handle->handle.stream.handle = phar;
+ file_handle->handle.stream.reader = phar_zend_stream_reader;
file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */
- file_handle->handle.stream.fteller = stream_fteller_for_zend;
+ file_handle->handle.stream.fteller = phar_stream_fteller_for_zend;
file_handle->handle.stream.interactive = 0;
- php_stream_rewind(phar->fp);
+ phar->is_persistent ?
+ php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
+ php_stream_rewind(phar->fp);
#endif
}
}
}
+
zend_try {
failed = 0;
res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
} zend_catch {
failed = 1;
} zend_end_try();
+
if (name) {
efree(name);
}
+
if (failed) {
zend_bailout();
}
+
return res;
}
/* }}} */
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
+
if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+ if (!pphar && PHAR_G(manifest_cached)) {
+ zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+ }
efree(arch);
efree(entry);
}
}
+
/* retrieving an include within the current directory, so use this if possible */
if (!(entry = phar_find_in_include_path((char *) filename, strlen(filename), NULL TSRMLS_CC))) {
/* this file is not in the phar, use the original path */
goto skip_phar;
}
+
if (SUCCESS == phar_orig_zend_open(entry, handle TSRMLS_CC)) {
if (!handle->opened_path) {
handle->opened_path = entry;
}
return SUCCESS;
}
+
if (entry != filename) {
efree(entry);
}
+
return FAILURE;
}
skip_phar:
PHP_MINIT_FUNCTION(phar) /* {{{ */
{
+ phar_mime_type mime;
+
ZEND_INIT_MODULE_GLOBALS(phar, php_phar_init_globals_module, NULL);
REGISTER_INI_ENTRIES();
phar_object_init(TSRMLS_C);
+ phar_intercept_functions_init(TSRMLS_C);
+
+ zend_hash_init(&PHAR_G(mime_types), 0, NULL, NULL, 1);
+
+#define PHAR_SET_MIME(mimetype, ret, fileext) \
+ mime.mime = mimetype; \
+ mime.len = sizeof((mimetype))+1; \
+ mime.type = ret; \
+ zend_hash_add(&PHAR_G(mime_types), fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
+
+ PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
+ PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
+ PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
+ PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
+ PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
+ PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
+ PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
+ PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
+ PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
+ PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
+ PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
+ PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
+ PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
+ PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
+ PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
+ PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
+ PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
+ PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
+ PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
+ PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
+ PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
+ PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
+ PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
+ PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
+
return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
}
/* }}} */
PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
{
- return php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
+ php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
+
+ zend_hash_destroy(&PHAR_G(mime_types));
+
+ phar_intercept_functions_shutdown(TSRMLS_C);
+
if (zend_compile_file == phar_compile_file) {
zend_compile_file = phar_orig_compile_file;
}
zend_stream_open_function = phar_orig_zend_open;
}
#endif
+ if (PHAR_G(manifest_cached)) {
+ zend_hash_destroy(&(cached_phars));
+ zend_hash_destroy(&(cached_alias));
+ }
+
+ return SUCCESS;
}
/* }}} */
{
if (!PHAR_GLOBALS->request_init)
{
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
PHAR_GLOBALS->request_init = 1;
PHAR_GLOBALS->request_ends = 0;
PHAR_GLOBALS->request_done = 0;
- zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 0);
- zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 0);
- zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), sizeof(const char *), zend_get_hash_value, NULL, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
+
+ if (PHAR_G(manifest_cached)) {
+ phar_archive_data **pphar;
+ phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
+
+ for (zend_hash_internal_pointer_reset(&cached_phars);
+ zend_hash_get_current_data(&cached_phars, (void **)&pphar) == SUCCESS;
+ zend_hash_move_forward(&cached_phars)) {
+ stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
+ }
+
+ PHAR_GLOBALS->cached_fp = stuff;
+ }
+
+ PHAR_GLOBALS->phar_SERVER_mung_list = 0;
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
PHAR_G(cwd_init) = 0;
PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
{
+ int i;
+
PHAR_GLOBALS->request_ends = 1;
+
if (PHAR_GLOBALS->request_init)
{
phar_release_functions(TSRMLS_C);
PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
- zend_hash_destroy(&(PHAR_GLOBALS->phar_SERVER_mung_list));
- PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets = NULL;
+ PHAR_GLOBALS->phar_SERVER_mung_list = 0;
+
+ if (PHAR_GLOBALS->cached_fp) {
+ for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
+ if (PHAR_GLOBALS->cached_fp[i].fp) {
+ php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
+ }
+ if (PHAR_GLOBALS->cached_fp[i].ufp) {
+ php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
+ }
+ efree(PHAR_GLOBALS->cached_fp[i].manifest);
+ }
+ efree(PHAR_GLOBALS->cached_fp);
+ PHAR_GLOBALS->cached_fp = 0;
+ }
+
PHAR_GLOBALS->request_init = 0;
+
if (PHAR_G(cwd)) {
efree(PHAR_G(cwd));
}
+
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
PHAR_G(cwd_init) = 0;
}
+
PHAR_GLOBALS->request_done = 1;
return SUCCESS;
}
php_info_print_table_row(2, "Phar-based phar archives", "enabled");
php_info_print_table_row(2, "Tar-based phar archives", "enabled");
php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
+
if (PHAR_G(has_zlib)) {
php_info_print_table_row(2, "gzip compression", "enabled");
} else {
php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
}
+
if (PHAR_G(has_bz2)) {
php_info_print_table_row(2, "bzip2 compression", "enabled");
} else {
php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
}
+#ifdef PHAR_HAVE_OPENSSL
+ php_info_print_table_row(2, "Native OpenSSL support", "enabled");
+#else
+ if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
+ php_info_print_table_row(2, "OpenSSL support", "enabled");
+ } else {
+ php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
+ }
+#endif
php_info_print_table_end();
php_info_print_box_start(0);
PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
- PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
+ PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
- PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
- PUTS("Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.");
+ PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
+ PUTS("Portions of tar implementation Copyright (c) 2003-2008 Tim Kientzle.");
php_info_print_box_end();
DISPLAY_INI_ENTRIES();
*/
static zend_module_dep phar_deps[] = {
ZEND_MOD_OPTIONAL("apc")
+ ZEND_MOD_OPTIONAL("bz2")
+ ZEND_MOD_OPTIONAL("openssl")
+ ZEND_MOD_OPTIONAL("zlib")
+ ZEND_MOD_OPTIONAL("standard")
#if HAVE_SPL
ZEND_MOD_REQUIRED("spl")
#endif
+----------------------------------------------------------------------+
| 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 |
#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 */
#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 */
#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;
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)
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 */
/* 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;
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) */
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;
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;
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'
zend_object std;
spl_filesystem_object spl;
struct {
- zend_object std;
- phar_archive_data *archive;
+ zend_object std;
+ phar_archive_data *archive;
} arc;
};
#endif
zend_object std;
spl_filesystem_object spl;
struct {
- zend_object std;
- phar_entry_info *entry;
+ zend_object std;
+ phar_entry_info *entry;
} ent;
};
#endif
#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()
}
/* }}} */
+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);
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);
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);
#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);
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 {
+----------------------------------------------------------------------+
| phar php single-file executable PHP extension |
+----------------------------------------------------------------------+
- | Copyright (c) 2005-2007 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 |
}
/* }}} */
-static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int basename_len, char *request_uri, int request_uri_len TSRMLS_DC) /* {{{ */
+static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, char *request_uri, int request_uri_len TSRMLS_DC) /* {{{ */
{
- zval **_SERVER, **stuff;
+ HashTable *_SERVER;
+ zval **stuff;
char *path_info;
+ int basename_len = strlen(basename);
/* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
- if (SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &_SERVER)) {
+ if (!PG(http_globals)[TRACK_VARS_SERVER]) {
return;
}
+ _SERVER = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
+
/* PATH_INFO and PATH_TRANSLATED should always be munged */
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
- int code;
- zval *temp;
- char newname[] = "PHAR_PATH_INFO";
+ if (SUCCESS == zend_hash_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
+ int code;
+ zval *temp;
path_info = Z_STRVAL_PP(stuff);
code = Z_STRLEN_PP(stuff);
+
if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) {
ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1);
- MAKE_STD_ZVAL(temp);
+ MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ zend_hash_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO"), (void *) &temp, sizeof(zval **), NULL);
}
}
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
- int code;
- zval *temp;
- char newname[] = "PHAR_PATH_TRANSLATED";
- path_info = Z_STRVAL_PP(stuff);
- code = Z_STRLEN_PP(stuff);
+ if (SUCCESS == zend_hash_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ zend_hash_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED"), (void *) &temp, sizeof(zval **), NULL);
}
- if (!PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_SERVER_mung_list))) {
+
+ if (!PHAR_GLOBALS->phar_SERVER_mung_list) {
return;
}
- if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
+
+ if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_REQUEST_URI) {
+ if (SUCCESS == zend_hash_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
int code;
zval *temp;
- char newname[] = "PHAR_REQUEST_URI";
path_info = Z_STRVAL_PP(stuff);
code = Z_STRLEN_PP(stuff);
+
if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ zend_hash_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI"), (void *) &temp, sizeof(zval **), NULL);
}
}
}
- if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) {
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
+
+ if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_PHP_SELF) {
+ if (SUCCESS == zend_hash_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
int code;
zval *temp;
- char newname[] = "PHAR_PHP_SELF";
path_info = Z_STRVAL_PP(stuff);
code = Z_STRLEN_PP(stuff);
+
if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ zend_hash_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF"), (void *) &temp, sizeof(zval **), NULL);
}
}
}
- if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
- int code;
- zval *temp;
- char newname[] = "PHAR_SCRIPT_NAME";
-
- path_info = Z_STRVAL_PP(stuff);
- code = Z_STRLEN_PP(stuff);
+ if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_NAME) {
+ if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
ZVAL_STRINGL(*stuff, entry, entry_len, 1);
-
+
MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
- }
+ zend_hash_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME"), (void *) &temp, sizeof(zval **), NULL);
+ }
}
- if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
- int code;
- zval *temp;
- char newname[] = "PHAR_SCRIPT_FILENAME";
+ if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_FILENAME) {
+ if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
+ int code;
+ zval *temp;
- path_info = Z_STRVAL_PP(stuff);
- code = Z_STRLEN_PP(stuff);
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
MAKE_STD_ZVAL(temp);
ZVAL_STRINGL(temp, path_info, code, 0);
- zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ zend_hash_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME"), (void *) &temp, sizeof(zval **), NULL);
}
}
}
/* }}} */
-static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, int basename_len, char *ru, int ru_len TSRMLS_DC) /* {{{ */
+static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, char *ru, int ru_len TSRMLS_DC) /* {{{ */
{
char *name = NULL, buf[8192], *cwd;
zend_syntax_highlighter_ini syntax_highlighter_ini;
sapi_header_line ctr = {0};
size_t got;
- int dummy = 1, name_len, ret;
+ int dummy = 1, name_len;
zend_file_handle file_handle;
zend_op_array *new_op_array;
zval *result = NULL;
+ php_stream *fp;
+ off_t position;
switch (code) {
case PHAR_MIME_PHPS:
highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
- phar_entry_delref(phar TSRMLS_CC);
efree(name);
#ifdef PHP_WIN32
efree(arch);
ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
efree(ctr.line);
- ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", phar->internal_file->uncompressed_filesize);
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", info->uncompressed_filesize);
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
efree(ctr.line);
+
if (FAILURE == sapi_send_headers(TSRMLS_C)) {
- phar_entry_delref(phar TSRMLS_CC);
zend_bailout();
}
/* prepare to output */
- if (!phar_get_efp(phar->internal_file, 1 TSRMLS_CC)) {
+ fp = phar_get_efp(info, 1 TSRMLS_CC);
+
+ if (!fp) {
char *error;
- if (!phar_open_jit(phar->phar, phar->internal_file, phar->phar->fp, &error, 0 TSRMLS_CC)) {
+ if (!phar_open_jit(phar, info, phar_get_pharfp(phar TSRMLS_CC), &error, 0 TSRMLS_CC)) {
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
return -1;
}
- phar->fp = phar_get_efp(phar->internal_file, 1 TSRMLS_CC);
- phar->zero = phar->internal_file->offset;
+ fp = phar_get_efp(info, 1 TSRMLS_CC);
}
- phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ position = 0;
+ phar_seek_efp(info, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+
do {
- got = php_stream_read(phar->fp, buf, MIN(8192, phar->internal_file->uncompressed_filesize - phar->position));
- PHPWRITE(buf, got);
- phar->position = php_stream_tell(phar->fp) - phar->zero;
- if (phar->position == (off_t) phar->internal_file->uncompressed_filesize) {
- break;
+ got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
+ if (got > 0) {
+ PHPWRITE(buf, got);
+ position += got;
+ if (position == (off_t) info->uncompressed_filesize) {
+ break;
+ }
}
} while (1);
- phar_entry_delref(phar TSRMLS_CC);
zend_bailout();
case PHAR_MIME_PHP:
if (basename) {
- phar_mung_server_vars(arch, entry, entry_len, basename, basename_len, ru, ru_len TSRMLS_CC);
+ phar_mung_server_vars(arch, entry, entry_len, basename, ru, ru_len TSRMLS_CC);
efree(basename);
}
- phar_entry_delref(phar TSRMLS_CC);
+
if (entry[0] == '/') {
name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
} else {
name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
}
- ret = php_stream_open_for_zend_ex(name, &file_handle, ENFORCE_SAFE_MODE|USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
-
- if (ret != SUCCESS) {
- efree(name);
- return -1;
- }
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.handle.fd = 0;
+ file_handle.filename = name;
+ file_handle.opened_path = NULL;
+ file_handle.free_filename = 0;
+
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
- if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
- if ((cwd = strrchr(entry, '/'))) {
+
+ if (zend_hash_add(&EG(included_files), name, name_len+1, (void *)&dummy, sizeof(int), NULL) == SUCCESS) {
+ if ((cwd = zend_memrchr(entry, '/', entry_len))) {
PHAR_G(cwd_init) = 1;
if (entry == cwd) {
/* root directory */
PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
}
}
+
new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
+
+ if (!new_op_array) {
+ zend_hash_del(&EG(included_files), name, name_len+1);
+ }
+
zend_destroy_file_handle(&file_handle TSRMLS_CC);
+
} else {
+ efree(name);
new_op_array = NULL;
-#if PHP_VERSION_ID >= 50300
- zend_file_handle_dtor(&file_handle TSRMLS_CC);
-#else
- zend_file_handle_dtor(&file_handle);
-#endif
}
#ifdef PHP_WIN32
efree(arch);
} zend_end_try();
destroy_op_array(new_op_array TSRMLS_CC);
efree(new_op_array);
+
if (PHAR_G(cwd)) {
efree(PHAR_G(cwd));
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
}
+
PHAR_G(cwd_init) = 0;
efree(name);
+
if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
zval_ptr_dtor(EG(return_value_ptr_ptr));
}
+
zend_bailout();
}
+
return PHAR_MIME_PHP;
}
return -1;
}
/* }}} */
-static void phar_do_404(char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */
+static void phar_do_404(phar_archive_data *phar, char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */
{
- int hi;
- phar_entry_data *phar;
- char *error;
- if (f404_len) {
- if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, f404, f404_len, "r", 0, &error, 1 TSRMLS_CC)) {
- if (error) {
- efree(error);
- }
- goto nofile;
+ sapi_header_line ctr = {0};
+ phar_entry_info *info;
+
+ if (phar && f404_len) {
+ info = phar_get_entry_info(phar, f404, f404_len, NULL, 1 TSRMLS_CC);
+
+ if (info) {
+ phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, fname_len, NULL, NULL, 0 TSRMLS_CC);
+ return;
}
- hi = phar_file_action(phar, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, fname_len, NULL, 0, NULL, 0 TSRMLS_CC);
- } else {
- sapi_header_line ctr = {0};
-nofile:
- ctr.response_code = 404;
- ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
- ctr.line = "HTTP/1.0 404 Not Found";
- sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
- sapi_send_headers(TSRMLS_C);
- PHPWRITE("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ", sizeof("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ") - 1);
- PHPWRITE(entry, entry_len);
- PHPWRITE(" Not Found</h1>\n </body>\n</html>", sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
}
+
+ ctr.response_code = 404;
+ ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
+ ctr.line = "HTTP/1.0 404 Not Found";
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ sapi_send_headers(TSRMLS_C);
+ PHPWRITE("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ", sizeof("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ") - 1);
+ PHPWRITE(entry, entry_len);
+ PHPWRITE(" Not Found</h1>\n </body>\n</html>", sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
}
/* }}} */
{
char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
int e_len = *entry_len - 1, u_len = 0;
- phar_archive_data **pphar;
+ phar_archive_data **pphar = NULL;
/* we already know we can retrieve the phar if we reach here */
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
+ if (!pphar && PHAR_G(manifest_cached)) {
+ zend_hash_find(&cached_phars, fname, fname_len, (void **) &pphar);
+ }
+
do {
if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
if (u) {
*entry_len = e_len + 1;
return;
}
+
if (u) {
u1 = strrchr(e, '/');
u[0] = '/';
return;
}
}
+
u[0] = '\0';
u_len = strlen(u + 1);
e_len -= u_len + 1;
+
if (e_len < 0) {
if (saveu) {
saveu[0] = '/';
RETURN_STRINGL(arch, arch_len, 0);
}
}
+
RETURN_STRINGL("", 0, 1);
}
/* }}} */
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(fname, fname_len);
+#endif
+
if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
efree(entry);
entry = NULL;
+
if (path_len > 7 && !memcmp(path, "phar://", 7)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path);
efree(arch);
}
carry_on2:
if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, arch, arch_len, (void **)&pphar)) {
+ if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
+ goto carry_on;
+ }
+ }
+
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
+
if (arch) {
efree(arch);
}
if (path && path == entry) {
efree(entry);
}
+
if (arch) {
efree(arch);
}
+
return;
}
+
if (entry && path && path == entry) {
efree(entry);
}
+
if (arch) {
efree(arch);
}
+
return;
} else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
+ goto carry_on;
+ } else if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, fname, fname_len, (void **)&pphar)) {
+ if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
+ goto carry_on;
+ }
+
goto carry_on;
} else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
path = entry;
path_len = entry_len;
goto carry_on2;
}
+
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual);
}
/* }}} */
*/
PHP_METHOD(Phar, webPhar)
{
- HashTable mimetypes;
- phar_mime_type mime;
zval *mimeoverride = NULL, *rewrite = NULL;
char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0;
- char *fname, *basename, *path_info, *mime_type, *entry, *pt;
+ char *fname, *basename, *path_info, *mime_type = NULL, *entry, *pt;
int fname_len, entry_len, code, index_php_len = 0, not_cgi;
- phar_entry_data *phar;
+ phar_archive_data *phar = NULL;
+ phar_entry_info *info;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) {
return;
phar_request_initialize(TSRMLS_C);
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
+
if (phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) != SUCCESS) {
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
if (!(SG(request_info).request_method && SG(request_info).request_uri && (!strcmp(SG(request_info).request_method, "GET") || !strcmp(SG(request_info).request_method, "POST")))) {
return;
}
+
#ifdef PHP_WIN32
fname = estrndup(fname, fname_len);
phar_unixify_path_separators(fname, fname_len);
#endif
- basename = strrchr(fname, '/');
+ basename = zend_memrchr(fname, '/', fname_len);
+
if (!basename) {
basename = fname;
} else {
if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1))
|| (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) {
- char *testit;
- testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
- if (!(pt = strstr(testit, basename))) {
- efree(testit);
- return;
- }
- path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
- if (path_info) {
- entry = path_info;
- entry_len = strlen(entry);
- spprintf(&path_info, 0, "%s%s", testit, path_info);
- free_pathinfo = 1;
+ if (PG(http_globals)[TRACK_VARS_SERVER]) {
+ HashTable *ht = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
+ zval **z_script_name, **z_path_info;
+
+ if (SUCCESS != zend_hash_find(ht, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void**)&z_script_name) ||
+ IS_STRING != Z_TYPE_PP(z_script_name) ||
+ !strstr(Z_STRVAL_PP(z_script_name), basename)) {
+ return;
+ }
+
+ if (SUCCESS == zend_hash_find(ht, "PATH_INFO", sizeof("PATH_INFO"), (void**)&z_path_info) &&
+ IS_STRING == Z_TYPE_PP(z_path_info)) {
+ entry_len = Z_STRLEN_PP(z_path_info);
+ entry = estrndup(Z_STRVAL_PP(z_path_info), entry_len);
+ path_info = emalloc(Z_STRLEN_PP(z_script_name) + entry_len + 1);
+ memcpy(path_info, Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
+ memcpy(path_info + Z_STRLEN_PP(z_script_name), entry, entry_len + 1);
+ free_pathinfo = 1;
+ } else {
+ entry_len = 0;
+ entry = estrndup("", 0);
+ path_info = Z_STRVAL_PP(z_script_name);
+ }
+
+ pt = estrndup(Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
+
} else {
- path_info = testit;
- free_pathinfo = 1;
- entry = estrndup("", 0);
- entry_len = 0;
+ char *testit;
+
+ testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
+ if (!(pt = strstr(testit, basename))) {
+ efree(testit);
+ return;
+ }
+
+ path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
+
+ if (path_info) {
+ entry = path_info;
+ entry_len = strlen(entry);
+ spprintf(&path_info, 0, "%s%s", testit, path_info);
+ free_pathinfo = 1;
+ } else {
+ path_info = testit;
+ free_pathinfo = 1;
+ entry = estrndup("", 0);
+ entry_len = 0;
+ }
+
+ pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
}
- pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
not_cgi = 0;
} else {
path_info = SG(request_info).request_uri;
/* this can happen with rewrite rules - and we have no idea what to do then, so return */
return;
}
- entry_len = strlen(path_info);
+ entry_len = strlen(path_info);
entry_len -= (pt - path_info) + (fname_len - (basename - fname));
entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
#endif
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback");
+
if (free_pathinfo) {
efree(path_info);
}
+
return;
}
if (!EG(exception)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback");
}
+
if (free_pathinfo) {
efree(path_info);
}
+
return;
}
+
if (!fci.retval_ptr_ptr || !retval_ptr) {
if (free_pathinfo) {
efree(path_info);
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
return;
}
+
switch (Z_TYPE_P(retval_ptr)) {
#if PHP_VERSION_ID >= 60000
case IS_UNICODE:
#endif
case IS_STRING:
efree(entry);
+
if (fci.retval_ptr_ptr != &retval_ptr) {
entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr));
entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr);
entry = Z_STRVAL_P(retval_ptr);
entry_len = Z_STRLEN_P(retval_ptr);
}
+
break;
- case IS_BOOL :
+ case IS_BOOL:
phar_do_403(entry, entry_len TSRMLS_CC);
+
if (free_pathinfo) {
efree(path_info);
}
+
zend_bailout();
return;
default:
efree(retval_ptr);
+
if (free_pathinfo) {
efree(path_info);
}
+
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
return;
}
if (entry_len) {
phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC);
}
+
if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
efree(entry);
/* direct request */
entry = estrndup("/index.php", sizeof("/index.php"));
entry_len = sizeof("/index.php")-1;
}
- if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, NULL, 1 TSRMLS_CC)) {
- phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
+
+ if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
+ (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
+ phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
+
if (free_pathinfo) {
efree(path_info);
}
+
zend_bailout();
} else {
char *tmp, sa;
sa = *tmp;
*tmp = '\0';
}
+
ctr.response_code = 0;
+
if (path_info[strlen(path_info)-1] == '/') {
ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
} else {
ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
}
+
if (not_cgi) {
*tmp = sa;
}
+
if (free_pathinfo) {
efree(path_info);
}
+
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
sapi_send_headers(TSRMLS_C);
- phar_entry_delref(phar TSRMLS_CC);
efree(ctr.line);
zend_bailout();
}
}
- if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, &error, 1 TSRMLS_CC)) {
- phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
+ if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
+ (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
+ phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
#ifdef PHP_WIN32
efree(fname);
#endif
zend_bailout();
}
- /* set up mime types */
- zend_hash_init(&mimetypes, sizeof(phar_mime_type *), zend_get_hash_value, NULL, 0);
-#define PHAR_SET_MIME(mimetype, ret, fileext) \
- mime.mime = mimetype; \
- mime.len = sizeof((mimetype))+1; \
- mime.type = ret; \
- zend_hash_add(&mimetypes, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
-
- PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
- PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
- PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
- PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
- PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
- PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
- PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
- PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
- PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
- PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
- PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
- PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
- PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
- PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
- PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
- PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
- PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
- PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
- PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
- PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
- PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
- PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
- PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
- PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
- PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
- PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
- PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
- PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
- PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
- PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
- PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
-
- /* set up user overrides */
-#define PHAR_SET_USER_MIME(ret) \
- if (Z_TYPE_PP(val) == IS_LONG) { \
- mime.mime = ""; \
- mime.len = 0; \
- } else { \
- mime.mime = Z_STRVAL_PP(val); \
- mime.len = Z_STRLEN_PP(val); \
- } \
- mime.type = ret; \
- zend_hash_update(&mimetypes, str_key, keylen-1, (void *)&mime, sizeof(phar_mime_type), NULL);
-
- if (mimeoverride) {
- if (!zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
- goto no_mimes;
- }
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mimeoverride)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mimeoverride)); zend_hash_move_forward(Z_ARRVAL_P(mimeoverride))) {
- zval **val;
- phar_zstr key;
- char *str_key;
- uint keylen;
- ulong intkey;
-
- if (HASH_KEY_IS_LONG == zend_hash_get_current_key_ex(Z_ARRVAL_P(mimeoverride), &key, &keylen, &intkey, 0, NULL)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Key of MIME type overrides array must be a file extension, was \"%d\"", intkey);
- phar_entry_delref(phar TSRMLS_CC);
-#ifdef PHP_WIN32
- efree(fname);
-#endif
- RETURN_FALSE;
- }
+ if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
+ char *ext = zend_memrchr(entry, '.', entry_len);
+ zval **val;
- PHAR_STR(key, str_key);
+ if (ext) {
+ ++ext;
- if (FAILURE == zend_hash_get_current_data(Z_ARRVAL_P(mimeoverride), (void **) &val)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Failed to retrieve Mime type for extension \"%s\"", str_key);
- phar_entry_delref(phar TSRMLS_CC);
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val)) {
+ switch (Z_TYPE_PP(val)) {
+ case IS_LONG:
+ if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
+ mime_type = "";
+ code = Z_LVAL_PP(val);
+ } else {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed");
#ifdef PHP_WIN32
- efree(fname);
+ efree(fname);
#endif
- RETURN_FALSE;
- }
- switch (Z_TYPE_PP(val)) {
- case IS_LONG :
- if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
- PHAR_SET_USER_MIME((char) Z_LVAL_PP(val))
- } else {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed");
- phar_entry_delref(phar TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ break;
+ case IS_STRING:
+ mime_type = Z_STRVAL_PP(val);
+ code = PHAR_MIME_OTHER;
+ break;
+ default:
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed");
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_FALSE;
- }
- break;
-#if PHP_VERSION_ID >= 60000
- case IS_UNICODE:
- zval_unicode_to_string(*(val) TSRMLS_CC);
- /* break intentionally omitted */
-#endif
- case IS_STRING:
- PHAR_SET_USER_MIME(PHAR_MIME_OTHER)
- break;
- default :
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed");
- phar_entry_delref(phar TSRMLS_CC);
-#ifdef PHP_WIN32
- efree(fname);
-#endif
- RETURN_FALSE;
+ }
}
}
}
-no_mimes:
- code = phar_file_type(&mimetypes, entry, &mime_type TSRMLS_CC);
- zend_hash_destroy(&mimetypes);
- ret = phar_file_action(phar, mime_type, code, entry, entry_len, fname, fname_len, pt, strlen(pt), ru, ru_len TSRMLS_CC);
+ if (!mime_type) {
+ code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type TSRMLS_CC);
+ }
+ ret = phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, fname_len, pt, ru, ru_len TSRMLS_CC);
}
/* }}} */
PHP_METHOD(Phar, mungServer)
{
zval *mungvalues;
- int php_self = 0, request_uri = 0, script_name = 0, script_filename = 0;
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) {
return;
}
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
return;
}
+
if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
return;
return;
}
-#if PHP_VERSION_ID >= 60000
- if (Z_TYPE_PP(data) == IS_UNICODE) {
- zval_unicode_to_string(*(data) TSRMLS_CC);
- }
-#endif
-
if (Z_TYPE_PP(data) != IS_STRING) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
return;
}
- if (!php_self && Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
- if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add PHP_SELF to Phar::mungServer() list of values to mung");
- return;
- }
- php_self = 1;
+ if (Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
+ PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_PHP_SELF;
}
+
if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) {
- if (!request_uri && !strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
- if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add REQUEST_URI to Phar::mungServer() list of values to mung");
- return;
- }
- request_uri = 1;
+ if (!strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
+ PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_REQUEST_URI;
}
- if (!script_name && !strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
- if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_NAME to Phar::mungServer() list of values to mung");
- return;
- }
- script_name = 1;
+ if (!strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
+ PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_NAME;
}
}
- if (!script_filename && Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
- if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
- zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_FILENAME to Phar::mungServer() list of values to mung");
- return;
- }
- script_filename = 1;
+
+ if (Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
+ PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_FILENAME;
}
}
}
char *alias = NULL, *error;
int alias_len = 0;
long dataoffset = 0;
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
return;
}
phar_request_initialize(TSRMLS_C);
RETVAL_BOOL(phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) == SUCCESS);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
phar_request_initialize(TSRMLS_C);
RETVAL_BOOL(phar_open_from_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
} else {
RETURN_FALSE;
}
-
case PHAR_ENT_COMPRESSED_BZ2:
if (PHAR_G(has_bz2)) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
-
default:
if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) {
RETURN_TRUE;
{
char *fname;
const char *ext_str;
- int fname_len, ext_len;
+ int fname_len, ext_len, is_executable;
zend_bool executable = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &fname, &fname_len, &executable) == FAILURE) {
return;
}
- fname_len = executable;
- RETVAL_BOOL(phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, fname_len, 2, 1 TSRMLS_CC) == SUCCESS);
+ is_executable = executable;
+ RETVAL_BOOL(phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, is_executable, 2, 1 TSRMLS_CC) == SUCCESS);
}
/* }}} */
*/
static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
{
- phar_archive_delref((phar_archive_data *) object->oth TSRMLS_CC);
+ phar_archive_data *phar = (phar_archive_data *) object->oth;
+
+ if (!phar->is_persistent) {
+ phar_archive_delref(phar TSRMLS_CC);
+ }
+
object->oth = NULL;
}
/* }}} */
{
phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
- ++(phar_data->refcount);
+ if (!phar_data->is_persistent) {
+ ++(phar_data->refcount);
+ }
}
/* }}} */
static spl_other_handler phar_spl_foreign_handler = {
- phar_spl_foreign_dtor,
- phar_spl_foreign_clone
+ phar_spl_foreign_dtor,
+ phar_spl_foreign_clone
};
#endif /* HAVE_SPL */
#if !HAVE_SPL
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
#else
- char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname, *objname;
+ char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname;
int fname_len, alias_len = 0, arch_len, entry_len, is_data;
- long flags = 0, format = 0;
+#if PHP_VERSION_ID < 50300
+ long flags = 0;
+#else
+ long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
+#endif
+ long format = 0;
phar_archive_object *phar_obj;
phar_archive_data *phar_data;
zval *zobj = getThis(), arg1, arg2;
phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- PHAR_STR(phar_obj->std.ce->name, objname);
-
- if (!strncmp(objname, "PharData", 8)) {
- is_data = 1;
- } else {
- is_data = 0;
- }
+ is_data = instanceof_function(Z_OBJCE_P(zobj), phar_ce_data TSRMLS_CC);
if (is_data) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!l", &fname, &fname_len, &flags, &alias, &alias_len, &format) == FAILURE) {
efree(arch);
fname = save_fname;
}
+
if (entry) {
efree(entry);
}
+
if (error) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"%s", error);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Phar creation or opening failed");
}
+
return;
}
}
is_data = phar_data->is_data;
- ++(phar_data->refcount);
+
+ if (!phar_data->is_persistent) {
+ ++(phar_data->refcount);
+ }
+
phar_obj->arc.archive = phar_data;
phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
INIT_PZVAL(&arg1);
ZVAL_STRINGL(&arg1, fname, fname_len, 0);
+ INIT_PZVAL(&arg2);
+ ZVAL_LONG(&arg2, flags);
- if (ZEND_NUM_ARGS() > 1) {
- INIT_PZVAL(&arg2);
- ZVAL_LONG(&arg2, flags);
- zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
- &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
- } else {
- zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj),
- &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1);
+ zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
+ &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
+
+ if (!phar_data->is_persistent) {
+ phar_obj->arc.archive->is_data = is_data;
}
- phar_obj->arc.archive->is_data = is_data;
phar_obj->spl.info_class = phar_ce_entry;
-
efree(fname);
#endif /* HAVE_SPL */
}
add_next_index_stringl(return_value, "SHA-256", 7, 1);
add_next_index_stringl(return_value, "SHA-512", 7, 1);
#endif
+#if PHAR_HAVE_OPENSSL
+ add_next_index_stringl(return_value, "OpenSSL", 7, 1);
+#else
+ if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
+ add_next_index_stringl(return_value, "OpenSSL", 7, 1);
+ }
+#endif
}
/* }}} */
PHP_METHOD(Phar, getSupportedCompression)
{
array_init(return_value);
-
phar_request_initialize(TSRMLS_C);
+
if (PHAR_G(has_zlib)) {
add_next_index_stringl(return_value, "GZ", 2, 1);
}
+
if (PHAR_G(has_bz2)) {
add_next_index_stringl(return_value, "BZIP2", 5, 1);
}
efree(entry);
}
+ if (phar->is_persistent) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
+ return;
+ }
+
if (phar->refcount) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname);
return;
}
+
fname = estrndup(phar->fname, phar->fname_len);
+
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
phar_archive_delref(phar TSRMLS_CC);
unlink(fname);
efree(fname);
return; \
}
+struct _phar_t {
+ phar_archive_object *p;
+ zend_class_entry *c;
+ char *b;
+ uint l;
+ zval *ret;
+ int count;
+ php_stream *fp;
+};
+
static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
{
zval **value;
zend_uchar key_type;
zend_bool is_splfileinfo = 0, close_fp = 1;
ulong int_key;
- struct _t {
- phar_archive_object *p;
- zend_class_entry *c;
- char *b;
- uint l;
- zval *ret;
- } *p_obj = (struct _t*) puser;
+ struct _phar_t *p_obj = (struct _phar_t*) puser;
uint str_key_len, base_len = p_obj->l, fname_len;
phar_entry_data *data;
php_stream *fp;
long contents_len;
- char *fname, *error, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
+ char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
phar_zstr key;
char *str_key;
zend_class_entry *ce = p_obj->c;
char *str = "[stream]";
iter->funcs->get_current_data(iter, &value TSRMLS_CC);
+
if (EG(exception)) {
return ZEND_HASH_APPLY_STOP;
}
+
if (!value) {
/* failure in get_current_data */
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned no value", ce->name);
return ZEND_HASH_APPLY_STOP;
}
+
switch (Z_TYPE_PP(value)) {
#if PHP_VERSION_ID >= 60000
case IS_UNICODE:
break;
case IS_RESOURCE:
php_stream_from_zval_no_verify(fp, value);
+
if (!fp) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returned an invalid stream handle", ce->name);
return ZEND_HASH_APPLY_STOP;
}
+
if (iter->funcs->get_current_key) {
key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
- PHAR_STR(key, str_key);
+
+ if (key_type > 9) { /* IS_UNICODE == 10 */
+ spprintf(&str_key, 0, "%v", key);
+ } else {
+ PHAR_STR(key, str_key);
+ }
+
save = str_key;
- if (str_key[str_key_len - 1] == '\0') str_key_len--;
+
+ if (str_key[str_key_len - 1] == '\0') {
+ str_key_len--;
+ }
+
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
+
close_fp = 0;
opened = (char *) estrndup(str, sizeof("[stream]") + 1);
goto after_open_fp;
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returns an SplFileInfo object, so base directory must be specified", ce->name);
return ZEND_HASH_APPLY_STOP;
}
+
switch (intern->type) {
case SPL_FS_DIR:
#if PHP_VERSION_ID >= 60000
#endif
fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC);
+
if (Z_BVAL(dummy)) {
/* ignore directories */
efree(fname);
return ZEND_HASH_APPLY_KEEP;
}
+
test = expand_filepath(fname, NULL TSRMLS_CC);
+
if (test) {
efree(fname);
fname = test;
fname_len = strlen(fname);
}
+
save = fname;
is_splfileinfo = 1;
goto phar_spl_fileinfo;
}
}
/* fall-through */
- default :
+ default:
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid value (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
temp = expand_filepath(base, NULL TSRMLS_CC);
base = temp;
base_len = strlen(base);
+
if (strstr(fname, base)) {
str_key_len = fname_len - base_len;
+
if (str_key_len <= 0) {
if (save) {
efree(save);
}
return ZEND_HASH_APPLY_KEEP;
}
+
str_key = fname + base_len;
+
if (*str_key == '/' || *str_key == '\\') {
str_key++;
str_key_len--;
}
+
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that is not in the base directory \"%s\"", ce->name, fname, base);
+
if (save) {
efree(save);
efree(temp);
}
+
return ZEND_HASH_APPLY_STOP;
}
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
- PHAR_STR(key, str_key);
+
+ if (key_type > 9) { /* IS_UNICODE == 10 */
+ spprintf(&str_key, 0, "%v", key);
+ } else {
+ PHAR_STR(key, str_key);
+ }
+
save = str_key;
+
if (str_key[str_key_len - 1] == '\0') str_key_len--;
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
#if PHP_MAJOR_VERSION < 6
if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that safe mode prevents opening", ce->name, fname);
+
if (save) {
efree(save);
}
+
if (temp) {
efree(temp);
}
+
return ZEND_HASH_APPLY_STOP;
}
#endif
if (php_check_open_basedir(fname TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a path \"%s\" that open_basedir prevents opening", ce->name, fname);
+
if (save) {
efree(save);
}
+
if (temp) {
efree(temp);
}
+
return ZEND_HASH_APPLY_STOP;
}
/* try to open source file, then create internal phar file and copy contents */
fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened);
+
if (!fp) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned a file that could not be opened \"%s\"", ce->name, fname);
+
if (save) {
efree(save);
}
+
if (temp) {
efree(temp);
}
+
return ZEND_HASH_APPLY_STOP;
}
-
after_open_fp:
if (str_key_len >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
/* silently skip any files that would be added to the magic .phar directory */
if (save) {
efree(save);
}
+
if (temp) {
efree(temp);
}
+
if (opened) {
efree(opened);
}
+
if (close_fp) {
php_stream_close(fp);
}
+
return ZEND_HASH_APPLY_KEEP;
}
+
if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error, 1 TSRMLS_CC))) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error);
efree(error);
+
if (save) {
efree(save);
}
+
if (opened) {
efree(opened);
}
+
if (temp) {
efree(temp);
}
+
if (close_fp) {
php_stream_close(fp);
}
+
return ZEND_HASH_APPLY_STOP;
+
} else {
if (error) {
efree(error);
}
- contents_len = php_stream_copy_to_stream(fp, data->fp, PHP_STREAM_COPY_ALL);
+ /* convert to PHAR_UFP */
+ if (data->internal_file->fp_type == PHAR_MOD) {
+ php_stream_close(data->internal_file->fp);
+ }
+
+ data->internal_file->fp = NULL;
+ data->internal_file->fp_type = PHAR_UFP;
+ data->internal_file->offset_abs = data->internal_file->offset = php_stream_tell(p_obj->fp);
+ data->fp = NULL;
+ contents_len = php_stream_copy_to_stream(fp, p_obj->fp, PHP_STREAM_COPY_ALL);
+ data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize =
+ php_stream_tell(p_obj->fp) - data->internal_file->offset;
}
+
if (close_fp) {
php_stream_close(fp);
}
if (save) {
efree(save);
}
+
if (temp) {
efree(temp);
}
data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
phar_entry_delref(data TSRMLS_CC);
+
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
int dir_len, regex_len = 0;
zend_bool apply_reg = 0;
zval arg, arg2, *iter, *iteriter, *regexiter = NULL;
- struct {
- phar_archive_object *p;
- zend_class_entry *c;
- char *b;
- uint l;
- zval *ret;
- } pass;
+ struct _phar_t pass;
PHAR_ARCHIVE_OBJECT();
INIT_PZVAL(&arg);
ZVAL_STRINGL(&arg, dir, dir_len, 0);
+ INIT_PZVAL(&arg2);
+#if PHP_VERSION_ID < 50300
+ ZVAL_LONG(&arg2, 0);
+#else
+ ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS);
+#endif
- zend_call_method_with_1_params(&iter, spl_ce_RecursiveDirectoryIterator,
- &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg);
+ zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator,
+ &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2);
if (EG(exception)) {
zval_ptr_dtor(&iter);
if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) {
zval_ptr_dtor(&iter);
+ zval_ptr_dtor(&iteriter);
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
RETURN_FALSE;
}
MAKE_STD_ZVAL(regexiter);
if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) {
+ zval_ptr_dtor(&iteriter);
zval_dtor(regexiter);
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname);
RETURN_FALSE;
pass.p = phar_obj;
pass.b = dir;
pass.l = dir_len;
+ pass.count = 0;
pass.ret = return_value;
+ pass.fp = php_stream_fopen_tmpfile();
if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
zval_ptr_dtor(&iteriter);
+
if (apply_reg) {
zval_ptr_dtor(®exiter);
}
+
+ phar_obj->arc.archive->ufp = pass.fp;
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
+
+ } else {
+ zval_ptr_dtor(&iteriter);
+ php_stream_close(pass.fp);
}
}
+/* }}} */
/* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory])
* Construct a phar archive from an iterator. The iterator must return a series of strings
char *error;
uint base_len = 0;
char *base = NULL;
- struct {
- phar_archive_object *p;
- zend_class_entry *c;
- char *b;
- uint l;
- zval *ret;
- } pass;
+ struct _phar_t pass;
+
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
pass.b = base;
pass.l = base_len;
pass.ret = return_value;
+ pass.count = 0;
+ pass.fp = php_stream_fopen_tmpfile();
if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
+ phar_obj->arc.archive->ufp = pass.fp;
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
+ } else {
+ php_stream_close(pass.fp);
}
-
}
/* }}} */
PHP_METHOD(Phar, count)
{
PHAR_ARCHIVE_OBJECT();
-
+
RETURN_LONG(zend_hash_num_elements(&phar_obj->arc.archive->manifest));
}
/* }}} */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
RETURN_FALSE;
}
+
switch (type) {
case PHAR_FORMAT_TAR:
RETURN_BOOL(phar_obj->arc.archive->is_tar);
}
return FAILURE;
}
+
/* copy old contents in entirety */
phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
offset = php_stream_tell(fp);
link = phar_get_link_source(entry TSRMLS_CC);
+
if (!link) {
link = entry;
}
+
if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
return FAILURE;
}
+
if (entry->fp_type == PHAR_MOD) {
/* save for potential restore on error */
entry->cfp = entry->fp;
entry->fp = NULL;
}
+
/* set new location of file contents */
entry->fp_type = PHAR_FP;
entry->offset = offset;
}
/* }}} */
-static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC)
+static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC) /* {{{ */
{
char *oldname = NULL, *oldpath = NULL;
char *basename = NULL, *basepath = NULL;
if (!ext) {
if (phar->is_zip) {
+
if (phar->is_data) {
ext = "zip";
} else {
ext = "phar.zip";
}
+
} else if (phar->is_tar) {
+
switch (phar->flags) {
case PHAR_FILE_COMPRESSED_GZ:
if (phar->is_data) {
}
}
} else {
+
switch (phar->flags) {
case PHAR_FILE_COMPRESSED_GZ:
ext = "phar.gz";
}
}
} else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) {
+
if (phar->is_data) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
} else {
}
oldpath = estrndup(phar->fname, phar->fname_len);
- oldname = strrchr(phar->fname, '/');
+ oldname = zend_memrchr(phar->fname, '/', phar->fname_len);
++oldname;
basename = estrndup(oldname, strlen(oldname));
efree(basepath);
efree(newname);
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, newpath, phar->fname_len, (void **) &pphar)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
+ return NULL;
+ }
+
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void **) &pphar)) {
if ((*pphar)->fname_len == phar->fname_len && !memcmp((*pphar)->fname, phar->fname, phar->fname_len)) {
if (!zend_hash_num_elements(&phar->manifest)) {
goto its_ok;
}
}
+
efree(oldpath);
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
return NULL;
}
-
its_ok:
if (!phar->is_data) {
if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext);
return NULL;
}
+
if (phar->alias) {
if (phar->is_temporary_alias) {
phar->alias = NULL;
zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL);
}
}
+
} else {
+
if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) {
efree(oldpath);
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
return NULL;
}
+
phar->alias = NULL;
phar->alias_len = 0;
}
}
phar_flush(phar, 0, 0, 1, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
efree(error);
}
MAKE_STD_ZVAL(ret);
+
if (SUCCESS != object_init_ex(ret, ce)) {
zval_dtor(ret);
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname);
return NULL;
}
+
INIT_PZVAL(&arg1);
ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len, 0);
zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1);
-
return ret;
}
+/* }}} */
static zval *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, php_uint32 flags TSRMLS_DC) /* {{{ */
{
phar_entry_info *entry, newentry;
zval *ret;
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
/* set whole-archive compression and type from parameter */
phar->flags = flags;
-
phar->is_data = source->is_data;
+
switch (convert) {
- case PHAR_FORMAT_TAR :
+ case PHAR_FORMAT_TAR:
phar->is_tar = 1;
break;
- case PHAR_FORMAT_ZIP :
+ case PHAR_FORMAT_ZIP:
phar->is_zip = 1;
break;
- default :
+ default:
phar->is_data = 0;
break;
}
zend_hash_init(&(phar->manifest), sizeof(phar_entry_info),
zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_init(&phar->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ zend_hash_init(&phar->virtual_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
phar->fp = php_stream_fopen_tmpfile();
phar->fname = source->fname;
phar->fname_len = source->fname_len;
phar->is_temporary_alias = source->is_temporary_alias;
phar->alias = source->alias;
+
/* first copy each file's uncompressed contents to a temporary file and set per-file flags */
for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) {
"Cannot convert phar archive \"%s\"", source->fname);
return NULL;
}
+
newentry = *entry;
+
if (newentry.link) {
newentry.link = estrdup(newentry.link);
goto no_copy;
}
+
if (newentry.tmp) {
newentry.tmp = estrdup(newentry.tmp);
goto no_copy;
}
+
newentry.metadata_str.c = 0;
+
if (FAILURE == phar_copy_file_contents(&newentry, phar->fp TSRMLS_CC)) {
zend_hash_destroy(&(phar->manifest));
php_stream_close(phar->fp);
}
no_copy:
newentry.filename = estrndup(newentry.filename, newentry.filename_len);
+
if (newentry.metadata) {
zval *t;
newentry.metadata_str.c = NULL;
newentry.metadata_str.len = 0;
}
+
newentry.is_zip = phar->is_zip;
newentry.is_tar = phar->is_tar;
+
if (newentry.is_tar) {
newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE);
}
+
newentry.is_modified = 1;
newentry.phar = phar;
- newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
+ newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
+ phar_set_inode(&newentry TSRMLS_CC);
zend_hash_add(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
+ phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len TSRMLS_CC);
}
if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) {
return ret;
} else {
zend_hash_destroy(&(phar->manifest));
+ zend_hash_destroy(&(phar->mounted_dirs));
+ zend_hash_destroy(&(phar->virtual_dirs));
php_stream_close(phar->fp);
efree(phar->fname);
efree(phar);
/* }}} */
/* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]])
- * Convert a phar.tar or phar.zip archive to the phar file format. The
+ * Convert a phar.tar or phar.zip archive to the phar file format. The
* optional parameter allows the user to determine the new
* filename extension (default is phar).
*/
"Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
return;
}
+
if (!PHAR_G(has_zlib)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
return;
}
+
flags = PHAR_FILE_COMPRESSED_GZ;
break;
-
case PHAR_ENT_COMPRESSED_BZ2:
if (format == PHAR_FORMAT_ZIP) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
return;
}
+
if (!PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
return;
}
+
flags = PHAR_FILE_COMPRESSED_BZ2;
break;
default:
phar_obj->arc.archive->is_data = 0;
ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
phar_obj->arc.archive->is_data = is_data;
+
if (ret) {
RETURN_ZVAL(ret, 1, 1);
} else {
"Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
return;
}
+
if (!PHAR_G(has_zlib)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
return;
}
+
flags = PHAR_FILE_COMPRESSED_GZ;
break;
-
case PHAR_ENT_COMPRESSED_BZ2:
if (format == PHAR_FORMAT_ZIP) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
return;
}
+
if (!PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
return;
}
+
flags = PHAR_FILE_COMPRESSED_BZ2;
break;
default:
phar_obj->arc.archive->is_data = 1;
ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
phar_obj->arc.archive->is_data = is_data;
+
if (ret) {
RETURN_ZVAL(ret, 1, 1);
} else {
PHP_METHOD(Phar, isCompressed)
{
PHAR_ARCHIVE_OBJECT();
-
+
if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_GZ) {
RETURN_LONG(PHAR_ENT_COMPRESSED_GZ);
}
+
if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_BZ2) {
RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2);
}
+
RETURN_FALSE;
}
/* }}} */
{
php_stream_statbuf ssb;
PHAR_ARCHIVE_OBJECT();
-
+
if (!phar_obj->arc.archive->is_writeable) {
RETURN_FALSE;
}
+
if (SUCCESS != php_stream_stat_path(phar_obj->arc.archive->fname, &ssb)) {
if (phar_obj->arc.archive->is_brandnew) {
/* assume it works if the file doesn't exist yet */
}
RETURN_FALSE;
}
+
RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0);
}
/* }}} */
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
-
+
RETURN_TRUE;
}
/* }}} */
char *alias, *error, *oldalias;
phar_archive_data **fd_ptr;
int alias_len, oldalias_len, old_temp, readd = 0;
+
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
RETURN_FALSE;
}
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
if (phar_obj->arc.archive->is_data) {
- zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
- "A Phar alias cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar alias cannot be set in a plain tar archive");
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar alias cannot be set in a plain zip archive");
+ }
RETURN_FALSE;
}
oldalias = phar_obj->arc.archive->alias;
oldalias_len = phar_obj->arc.archive->alias_len;
old_temp = phar_obj->arc.archive->is_temporary_alias;
+
if (alias_len) {
phar_obj->arc.archive->alias = estrndup(alias, alias_len);
} else {
phar_obj->arc.archive->alias = NULL;
}
+
phar_obj->arc.archive->alias_len = alias_len;
phar_obj->arc.archive->is_temporary_alias = 0;
-
phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
+
if (error) {
phar_obj->arc.archive->alias = oldalias;
phar_obj->arc.archive->alias_len = oldalias_len;
efree(error);
RETURN_FALSE;
}
+
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
+
if (oldalias) {
efree(oldalias);
}
+
RETURN_TRUE;
}
PHP_METHOD(Phar, getVersion)
{
PHAR_ARCHIVE_OBJECT();
-
+
RETURN_STRING(phar_obj->arc.archive->version, 1);
}
/* }}} */
PHP_METHOD(Phar, startBuffering)
{
PHAR_ARCHIVE_OBJECT();
-
+
phar_obj->arc.archive->donotflush = 1;
}
/* }}} */
PHP_METHOD(Phar, isBuffering)
{
PHAR_ARCHIVE_OBJECT();
-
+
RETURN_BOOL(!phar_obj->arc.archive->donotflush);
}
/* }}} */
PHP_METHOD(Phar, stopBuffering)
{
char *error;
+
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
}
phar_obj->arc.archive->donotflush = 0;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
if (phar_obj->arc.archive->is_data) {
- zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
- "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain tar archive");
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain zip archive");
+ }
return;
}
}
} else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) {
phar_flush(phar_obj->arc.archive, stub, stub_len, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
+
RETURN_TRUE;
}
* files cannot be loaded via this kind of stub, no parameters are accepted
* when the Phar object is zip- or tar-based.
*/
- PHP_METHOD(Phar, setDefaultStub)
+PHP_METHOD(Phar, setDefaultStub)
{
char *index = NULL, *webindex = NULL, *error = NULL, *stub = NULL;
int index_len = 0, webindex_len = 0, created_stub = 0;
PHAR_ARCHIVE_OBJECT();
if (phar_obj->arc.archive->is_data) {
- zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
- "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain tar archive");
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain zip archive");
+ }
return;
}
}
if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) {
-
stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
if (error) {
}
RETURN_FALSE;
}
+
created_stub = 1;
}
}
/* }}} */
-/* {{{ proto array Phar::setSignatureAlgorithm(int sigtype)
+/* {{{ proto array Phar::setSignatureAlgorithm(int sigtype[, string privatekey])
* Sets the signature algorithm for a phar and applies it. The signature
* algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256,
- * Phar::SHA512, or Phar::PGP (PGP is not yet supported and falls back to
- * SHA-1). Note that zip- and tar- based phar archives cannot support
- * signatures.
+ * Phar::SHA512, or Phar::OPENSSL. Note that zip- based phar archives
+ * cannot support signatures.
*/
PHP_METHOD(Phar, setSignatureAlgorithm)
{
long algo;
- char *error;
+ char *error, *key = NULL;
+ int key_len = 0;
+
PHAR_ARCHIVE_OBJECT();
-
+
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot set signature algorithm, phar is read-only");
return;
}
- if (phar_obj->arc.archive->is_tar) {
- zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
- "Cannot set signature algorithm, not possible with tar-based phar archives");
- return;
- }
+
if (phar_obj->arc.archive->is_zip) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot set signature algorithm, not possible with zip-based phar archives");
return;
}
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &algo) != SUCCESS) {
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &algo, &key, &key_len) != SUCCESS) {
return;
}
switch (algo) {
- case PHAR_SIG_SHA256 :
- case PHAR_SIG_SHA512 :
+ case PHAR_SIG_SHA256:
+ case PHAR_SIG_SHA512:
#if !HAVE_HASH_EXT
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled");
return;
#endif
- case PHAR_SIG_MD5 :
- case PHAR_SIG_SHA1 :
- case PHAR_SIG_PGP :
+ case PHAR_SIG_MD5:
+ case PHAR_SIG_SHA1:
+ case PHAR_SIG_OPENSSL:
phar_obj->arc.archive->sig_flags = algo;
phar_obj->arc.archive->is_modified = 1;
+ PHAR_G(openssl_privatekey) = key;
+ PHAR_G(openssl_privatekey_len) = key_len;
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
if (error) {
efree(error);
}
break;
- default :
+ default:
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Unknown signature algorithm specified");
}
PHAR_ARCHIVE_OBJECT();
if (phar_obj->arc.archive->signature) {
+ char *unknown;
+ int unknown_len;
+
array_init(return_value);
add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1);
switch(phar_obj->arc.archive->sig_flags) {
- case PHAR_SIG_MD5:
- add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1);
- break;
- case PHAR_SIG_SHA1:
- add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1);
- break;
- case PHAR_SIG_SHA256:
- add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1);
- break;
- case PHAR_SIG_SHA512:
- add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1);
- break;
+ case PHAR_SIG_MD5:
+ add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1);
+ break;
+ case PHAR_SIG_SHA1:
+ add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1);
+ break;
+ case PHAR_SIG_SHA256:
+ add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1);
+ break;
+ case PHAR_SIG_SHA512:
+ add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1);
+ break;
+ case PHAR_SIG_OPENSSL:
+ add_assoc_stringl(return_value, "hash_type", "OpenSSL", 7, 1);
+ break;
+ default:
+ unknown_len = spprintf(&unknown, 0, "Unknown (%d)", phar_obj->arc.archive->sig_flags);
+ add_assoc_stringl(return_value, "hash_type", unknown, unknown_len, 0);
+ break;
}
} else {
RETURN_FALSE;
if (entry->is_deleted) {
return ZEND_HASH_APPLY_KEEP;
}
+
entry->old_flags = entry->flags;
entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
entry->flags |= compress;
if (entry->is_deleted) {
return ZEND_HASH_APPLY_KEEP;
}
+
if (!PHAR_G(has_bz2)) {
if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
*(int *) argument = 0;
}
}
+
if (!PHAR_G(has_zlib)) {
if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
*(int *) argument = 0;
}
}
+
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */
{
int test;
+
test = 1;
zend_hash_apply_with_argument(manifest, phar_test_compression, &test TSRMLS_CC);
return test;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &method, &ext, &ext_len) == FAILURE) {
return;
}
-
+
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot compress phar archive, phar is read-only");
}
flags = PHAR_FILE_COMPRESSED_GZ;
break;
-
+
case PHAR_ENT_COMPRESSED_BZ2:
if (!PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
} else {
ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, flags TSRMLS_CC);
}
+
if (ret) {
RETURN_ZVAL(ret, 1, 1);
} else {
} else {
ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
}
+
if (ret) {
RETURN_ZVAL(ret, 1, 1);
} else {
"Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
return;
}
+
if (phar_obj->arc.archive->is_tar) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive");
return;
}
+
if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
if (flags == PHAR_FILE_COMPRESSED_GZ) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
}
return;
}
- pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC);
+ pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC);
phar_obj->arc.archive->is_modified = 1;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
efree(error);
"Phar is readonly, cannot change compression");
return;
}
+
if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed");
return;
}
+
if (phar_obj->arc.archive->is_tar) {
RETURN_TRUE;
} else {
}
phar_obj->arc.archive->is_modified = 1;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
efree(error);
}
+
RETURN_TRUE;
}
/* }}} */
const char *pcr_error;
int oldfile_len, newfile_len;
phar_entry_info *oldentry, newentry = {0}, *temp;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) {
}
memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info));
+
if (newentry.metadata) {
zval *t;
newentry.metadata_str.c = NULL;
newentry.metadata_str.len = 0;
}
+
newentry.filename = estrndup(newfile, newfile_len);
newentry.filename_len = newfile_len;
newentry.fp_refcount = 0;
zend_hash_add(&oldentry->phar->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
phar_obj->arc.archive->is_modified = 1;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
char *fname;
int fname_len;
phar_entry_info *entry;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get stub \".phar/stub.php\" directly in phar \"%s\", use getStub", phar_obj->arc.archive->fname);
return;
}
-
+
if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get alias \".phar/alias.txt\" directly in phar \"%s\", use getAlias", phar_obj->arc.archive->fname);
return;
}
-
+
if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot directly get any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname);
return;
efree(entry->filename);
efree(entry);
}
+
fname_len = spprintf(&fname, 0, "phar://%s/%s", phar_obj->arc.archive->fname, fname);
MAKE_STD_ZVAL(zfname);
ZVAL_STRINGL(zfname, fname, fname_len, 0);
spl_instantiate_arg_ex1(phar_obj->spl.info_class, &return_value, 0, zfname TSRMLS_CC);
zval_ptr_dtor(&zfname);
}
-
}
/* }}} */
if (error) {
efree(error);
}
+
if (!data->internal_file->is_dir) {
if (cont_str) {
contents_len = php_stream_write(data->fp, cont_str, cont_len);
}
contents_len = php_stream_copy_to_stream(contents_file, data->fp, PHP_STREAM_COPY_ALL);
}
+
data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
}
+
phar_entry_delref(data TSRMLS_CC);
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
} else {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created", dirname);
}
+
return;
} else {
if (error) {
efree(error);
}
+
phar_entry_delref(data TSRMLS_CC);
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
/* }}} */
-
/* {{{ proto int Phar::offsetSet(string entry, string value)
* set the contents of an internal file to those of an external file
*/
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
return;
}
-
+
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sr", &fname, &fname_len, &zresource) == FAILURE
&& zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) {
return;
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname);
return;
}
+
phar_add_file(phar_obj->arc.archive, fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC);
}
/* }}} */
/* entry is deleted, but has not been flushed to disk yet */
return;
}
+
entry->is_modified = 0;
entry->is_deleted = 1;
/* we need to "flush" the stream to save the newly deleted file on disk */
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
+
RETURN_TRUE;
}
} else {
{
char *dirname;
int dirname_len;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dirname, &dirname_len) == FAILURE) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create a directory in magic \".phar\" directory");
return;
}
+
phar_mkdir(phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC);
}
/* }}} */
int fname_len, localname_len = 0;
php_stream *resource;
zval *zresource;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive", fname);
return;
}
+
if (localname) {
fname = localname;
fname_len = localname_len;
{
char *localname, *cont_str;
int localname_len, cont_len;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) {
php_stream *fp;
php_stream_filter *filter = NULL;
phar_entry_info *stub;
+
PHAR_ARCHIVE_OBJECT();
if (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) {
php_stream_rewind(fp);
carry_on:
buf = safe_emalloc(len, 1, 1);
+
if (len != php_stream_read(fp, buf, len)) {
if (fp != phar_obj->arc.archive->fp) {
php_stream_close(fp);
efree(buf);
return;
}
+
if (filter) {
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
}
+
if (fp != phar_obj->arc.archive->fp) {
php_stream_close(fp);
}
- buf[len] = '\0';
+ buf[len] = '\0';
RETURN_STRINGL(buf, len, 0);
}
/* }}}*/
{
char *error;
zval *metadata;
+
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
MAKE_STD_ZVAL(phar_obj->arc.archive->metadata);
ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0);
phar_obj->arc.archive->is_modified = 1;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
PHP_METHOD(Phar, delMetadata)
{
char *error;
+
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
zval_ptr_dtor(&phar_obj->arc.archive->metadata);
phar_obj->arc.archive->metadata = NULL;
phar_obj->arc.archive->is_modified = 1;
-
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
} else {
RETURN_TRUE;
}
+
} else {
RETURN_TRUE;
}
#if (PHP_MAJOR_VERSION < 6)
#define OPENBASEDIR_CHECKPATH(filename) \
(PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
-#else
+#else
#define OPENBASEDIR_CHECKPATH(filename) \
php_check_open_basedir(filename TSRMLS_CC)
#endif
-static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC)
+static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC) /* {{{ */
{
php_stream_statbuf ssb;
int len;
/* silently ignore mounted entries */
return SUCCESS;
}
+
if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) {
return SUCCESS;
}
+
len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename);
+
if (len >= MAXPATHLEN) {
char *tmp;
/* truncate for error message */
efree(fullpath);
return FAILURE;
}
+
if (!len) {
spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
efree(fullpath);
efree(fullpath);
return FAILURE;
}
+
/* perform dirname */
- slash = strrchr(entry->filename, '/');
+ slash = zend_memrchr(entry->filename, '/', entry->filename_len);
+
if (slash) {
fullpath[dest_len + (slash - entry->filename) + 1] = '\0';
} else {
fullpath[dest_len] = '\0';
}
+
if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
if (entry->is_dir) {
if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
}
}
}
+
if (slash) {
fullpath[dest_len + (slash - entry->filename) + 1] = '/';
} else {
efree(fullpath);
return SUCCESS;
}
+/* }}} */
/* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
* Extract one or more file from a phar archive, optionally overwriting existing files
PHP_METHOD(Phar, extractTo)
{
char *error = NULL;
+ php_stream *fp;
php_stream_statbuf ssb;
phar_entry_info *entry;
- char *pathto, *filename;
+ char *pathto, *filename, *actual;
int pathto_len, filename_len;
int ret, i;
int nelems;
zval *zval_files = NULL;
zend_bool overwrite = 0;
+
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) {
return;
}
+ fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
+
+ if (!fp) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
+ "Invalid argument, %s cannot be found", phar_obj->arc.archive->fname);
+ return;
+ }
+
+ efree(actual);
+ php_stream_close(fp);
+
if (pathto_len < 1) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
"Invalid argument, extraction path must be non-zero length");
return;
}
+
if (pathto_len >= MAXPATHLEN) {
char *tmp = estrndup(pathto, 50);
/* truncate for error message */
"Invalid argument, expected a filename (string) or array of filenames");
return;
}
+
if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, filename, filename_len, (void **)&entry)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
"Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->arc.archive->fname);
return;
}
+
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
"Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
}
} else {
phar_archive_data *phar = phar_obj->arc.archive;
-
all_files:
/* Extract all files */
if (!zend_hash_num_elements(&(phar->manifest))) {
zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
zend_hash_move_forward(&phar->manifest)) {
phar_entry_info *entry;
+
if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
continue;
}
+
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
"Extraction from phar \"%s\" failed: %s", phar->fname, error);
{
char *fname, *arch, *entry, *error;
int fname_len, arch_len, entry_len;
- phar_entry_object *entry_obj;
- phar_entry_info *entry_info;
+ phar_entry_object *entry_obj;
+ phar_entry_info *entry_info;
phar_archive_data *phar_data;
zval *zobj = getThis(), arg1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
return;
}
-
+
entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
if (entry_obj->ent.entry) {
if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error, 1 TSRMLS_CC)) == NULL) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
- "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error?", ":"", error?error:"");
+ "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error ? ", " : "", error ? error : "");
efree(arch);
efree(entry);
return;
efree(entry_obj->ent.entry->filename);
entry_obj->ent.entry->filename = NULL;
}
+
efree(entry_obj->ent.entry);
entry_obj->ent.entry = NULL;
}
"Phar entry is a directory, does not have a CRC"); \
return;
}
+
if (entry_obj->ent.entry->is_crc_checked) {
RETURN_LONG(entry_obj->ent.entry->crc32);
} else {
PHP_METHOD(PharFileInfo, isCRCChecked)
{
PHAR_ENTRY_OBJECT();
-
+
RETURN_BOOL(entry_obj->ent.entry->is_crc_checked);
}
/* }}} */
PHP_METHOD(PharFileInfo, getPharFlags)
{
PHAR_ENTRY_OBJECT();
-
+
RETURN_LONG(entry_obj->ent.entry->flags & ~(PHAR_ENT_PERM_MASK|PHAR_ENT_COMPRESSION_MASK));
}
/* }}} */
"Phar entry \"%s\" is a temporary directory (not an actual entry in the archive), cannot chmod", entry_obj->ent.entry->filename); \
return;
}
+
if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot modify permissions for file \"%s\" in phar \"%s\", write operations are prohibited", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
return;
}
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perms) == FAILURE) {
return;
- }
- /* clear permissions */
+ }
+
+ /* clear permissions */
entry_obj->ent.entry->flags &= ~PHAR_ENT_PERM_MASK;
perms &= 0777;
entry_obj->ent.entry->flags |= perms;
entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
entry_obj->ent.entry->phar->is_modified = 1;
entry_obj->ent.entry->is_modified = 1;
+
/* hackish cache in php_stat needs to be cleared */
/* if this code fails to work, check main/streams/streams.c, _php_stream_stat_path */
if (BG(CurrentLStatFile)) {
efree(BG(CurrentLStatFile));
}
+
if (BG(CurrentStatFile)) {
efree(BG(CurrentStatFile));
}
+
BG(CurrentLStatFile) = NULL;
BG(CurrentStatFile) = NULL;
-
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
PHP_METHOD(PharFileInfo, hasMetadata)
{
PHAR_ENTRY_OBJECT();
-
+
RETURN_BOOL(entry_obj->ent.entry->metadata != NULL);
}
/* }}} */
PHP_METHOD(PharFileInfo, getMetadata)
{
PHAR_ENTRY_OBJECT();
-
+
if (entry_obj->ent.entry->metadata) {
RETURN_ZVAL(entry_obj->ent.entry->metadata, 1, 0);
}
{
char *error;
zval *metadata;
+
PHAR_ENTRY_OBJECT();
if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
return;
}
+
if (entry_obj->ent.entry->is_temp_dir) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
"Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata"); \
return;
}
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
return;
}
entry_obj->ent.entry->is_modified = 1;
entry_obj->ent.entry->phar->is_modified = 1;
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
PHP_METHOD(PharFileInfo, delMetadata)
{
char *error;
+
PHAR_ENTRY_OBJECT();
if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
return;
}
+
if (entry_obj->ent.entry->is_temp_dir) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
"Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata"); \
return;
}
+
if (entry_obj->ent.entry->metadata) {
zval_ptr_dtor(&entry_obj->ent.entry->metadata);
entry_obj->ent.entry->metadata = NULL;
entry_obj->ent.entry->phar->is_modified = 1;
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
} else {
RETURN_TRUE;
}
+
} else {
RETURN_TRUE;
}
char *error;
php_stream *fp;
phar_entry_info *link;
+
PHAR_ENTRY_OBJECT();
if (entry_obj->ent.entry->is_dir) {
"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
return;
}
+
link = phar_get_link_source(entry_obj->ent.entry TSRMLS_CC);
+
if (!link) {
link = entry_obj->ent.entry;
}
+
if (SUCCESS != phar_open_entry_fp(link, &error, 0 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
efree(error);
return;
}
+
if (!(fp = phar_get_efp(link, 0 TSRMLS_CC))) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
return;
}
+
phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC);
Z_TYPE_P(return_value) = IS_STRING;
Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0);
+
if (!Z_STRVAL_P(return_value)) {
Z_STRVAL_P(return_value) = estrndup("", 0);
}
"Cannot compress with Gzip compression, not possible with tar-based phar archives");
return;
}
+
if (entry_obj->ent.entry->is_dir) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
"Phar entry is a directory, cannot set compression"); \
return;
}
+
if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar is readonly, cannot change compression");
return;
}
+
if (entry_obj->ent.entry->is_deleted) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress deleted file");
RETURN_TRUE;
return;
}
+
if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0) {
if (!PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress with gzip compression, file is already compressed with bzip2 compression and bz2 extension is not enabled, cannot decompress");
return;
}
+
/* decompress this file indirectly */
if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
return;
}
}
+
if (!PHAR_G(has_zlib)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress with gzip compression, zlib extension is not enabled");
return;
}
+
entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_GZ;
RETURN_TRUE;
return;
}
+
if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0) {
if (!PHAR_G(has_zlib)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress with bzip2 compression, file is already compressed with gzip compression and zlib extension is not enabled, cannot decompress");
return;
}
+
/* decompress this file indirectly */
if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
return;
}
}
+
if (!PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress with bzip2 compression, bz2 extension is not enabled");
entry_obj->ent.entry->phar->is_modified = 1;
entry_obj->ent.entry->is_modified = 1;
-
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
+
RETURN_TRUE;
}
/* }}} */
"Phar entry is a directory, cannot set compression"); \
return;
}
+
if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK) == 0) {
RETURN_TRUE;
return;
}
+
if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar is readonly, cannot decompress");
return;
}
+
if (entry_obj->ent.entry->is_deleted) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot compress deleted file");
return;
}
+
if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0 && !PHAR_G(has_zlib)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot decompress Gzip-compressed file, zlib extension is not enabled");
return;
}
+
if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0 && !PHAR_G(has_bz2)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Cannot decompress Bzip2-compressed file, bz2 extension is not enabled");
return;
}
+
if (!entry_obj->ent.entry->fp) {
if (FAILURE == phar_open_archive_fp(entry_obj->ent.entry->phar TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot decompress entry \"%s\", phar error: Cannot open phar archive \"%s\" for reading", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
}
entry_obj->ent.entry->fp_type = PHAR_FP;
}
+
entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
entry_obj->ent.entry->phar->is_modified = 1;
entry_obj->ent.entry->is_modified = 1;
-
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setSigAlgo, 0, 0, 1)
ZEND_ARG_INFO(0, algorithm)
+ ZEND_ARG_INFO(0, privatekey)
ZEND_END_ARG_INFO();
static
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHP", PHAR_MIME_PHP)
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHPS", PHAR_MIME_PHPS)
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "MD5", PHAR_SIG_MD5)
- REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PGP", PHAR_SIG_PGP)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "OPENSSL", PHAR_SIG_OPENSSL)
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA1", PHAR_SIG_SHA1)
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA256", PHAR_SIG_SHA256)
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA512", PHAR_SIG_SHA512)
+----------------------------------------------------------------------+
| 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 |
+----------------------------------------------------------------------+
| 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 |
+----------------------------------------------------------------------+
| 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 |
#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;
#define PHP_PHAR_API
#endif
-#endif /* PHP_PHAR_H */
+#endif /* PHP_PHAR_H */
/*
};
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 */
};
/**
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) {
}
#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;
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)) {
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)
{
php_url_free(resource);
return NULL;
}
- }
+ }
return resource;
}
/* }}} */
*/
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;
}
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);
}
}
php_url_free(resource);
-
#if MBO_0
fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
fprintf(stderr, "Filename: %s\n", internal_file);
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;
}
/* }}} */
*/
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;
}
/* }}} */
{
phar_entry_data *data = (phar_entry_data *)stream->abstract;
size_t got;
-
+
if (data->internal_file->is_deleted) {
stream->eof = 1;
return 0;
data->position = php_stream_tell(data->fp) - data->zero;
stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize);
-
return got;
}
/* }}} */
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) {
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;
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;
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)) {
+ 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);
+ 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;
- }
- 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;
- }
+ }
+ /* 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);
- 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;
+ 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;
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);
phar_archive_data *phar, *pfrom, *pto;
phar_entry_info *entry;
uint host_len;
+ int is_dir = 0;
+ int is_modified = 0;
error = NULL;
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);
}
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);
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;
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
+ */
+----------------------------------------------------------------------+
| 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 |
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
}
/* }}} */
-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));
}
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) /* {{{ */
{
}
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;
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;
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) /* {{{ */
{
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);
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;
entry.is_crc_checked = 1;
entry.phar = myphar;
pos += sizeof(buf);
+
do {
phar_entry_info *newentry;
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];
} 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;
}
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 {
}
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 */
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)) {
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);
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);
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)) {
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) {
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;
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;
}
/* }}} */
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;
if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP;
}
+
if (entry->is_deleted) {
if (entry->fp_refcount <= 0) {
return ZEND_HASH_APPLY_REMOVE;
}
memset((char *) &header, 0, sizeof(header));
+
if (entry->filename_len > 100) {
if (entry->filename_len > 255) {
if (fp->error) {
} 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);
/* 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 */
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) {
}
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;
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);
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);
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;
}
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);
} 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);
}
}
return EOF;
}
+
len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5;
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);
}
}
}
}
-
nostub:
-
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
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");
}
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) {
}
}
}
+
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;
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);
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);
}
phar->is_brandnew = 0;
-
php_stream_rewind(newfile);
if (phar->donotflush) {
}
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 */
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);
}
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);
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
+ */
/* $Id$ */
#include "phar_internal.h"
+
+#ifdef PHAR_HAVE_OPENSSL
+/* OpenSSL includes */
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/crypto.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/conf.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/pkcs12.h>
+#else
+static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC);
+#endif
+
#if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
extern php_stream_wrapper php_stream_phar_wrapper;
#endif
/* for links to relative location, prepend cwd of the entry */
-static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC)
+static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
{
char *p, *ret = NULL;
if (!entry->link) {
}
return entry->link;
}
+/* }}} */
-phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC)
+phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
{
phar_entry_info *link_entry;
char *link = phar_get_link_location(entry TSRMLS_CC);
return NULL;
}
}
+/* }}} */
/* retrieve a phar_entry_info's current file pointer for reading contents */
-php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC)
+php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
{
if (follow_links && entry->link) {
phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
return phar_get_efp(link_entry, 1 TSRMLS_CC);
}
}
- if (entry->fp_type == PHAR_FP) {
- if (!entry->phar->fp) {
+
+ if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
+ if (!phar_get_entrypfp(entry TSRMLS_CC)) {
/* re-open just in time for cases where our refcount reached 0 on the phar archive */
phar_open_archive_fp(entry->phar TSRMLS_CC);
}
- return entry->phar->fp;
- } else if (entry->fp_type == PHAR_UFP) {
- return entry->phar->ufp;
+ return phar_get_entrypfp(entry TSRMLS_CC);
+ } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
+ return phar_get_entrypufp(entry TSRMLS_CC);
} else if (entry->fp_type == PHAR_MOD) {
return entry->fp;
} else {
return entry->fp;
}
}
+/* }}} */
-int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC)
+int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
{
php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
- off_t temp;
+ off_t temp, eoffset;
if (!fp) {
return -1;
}
+
if (follow_links) {
phar_entry_info *t;
t = phar_get_link_source(entry TSRMLS_CC);
entry = t;
}
}
+
if (entry->is_dir) {
return 0;
}
+
+ eoffset = phar_get_fp_offset(entry TSRMLS_CC);
+
switch (whence) {
- case SEEK_END :
- temp = entry->offset + entry->uncompressed_filesize + offset;
+ case SEEK_END:
+ temp = eoffset + entry->uncompressed_filesize + offset;
break;
- case SEEK_CUR :
- temp = entry->offset + position + offset;
+ case SEEK_CUR:
+ temp = eoffset + position + offset;
break;
- case SEEK_SET :
- temp = entry->offset + offset;
+ case SEEK_SET:
+ temp = eoffset + offset;
break;
}
- if (temp > entry->offset + (off_t) entry->uncompressed_filesize) {
+
+ if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
return -1;
}
- if (temp < entry->offset) {
+
+ if (temp < eoffset) {
return -1;
}
+
return php_stream_seek(fp, temp, SEEK_SET);
}
+/* }}} */
/* mount an absolute path or uri to a path internal to the phar archive */
-int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC)
+int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
{
phar_entry_info entry = {0};
php_stream_statbuf ssb;
filename_len = strlen(entry.tmp);
filename = entry.tmp;
+
/* only check openbasedir for files, not for phar streams */
if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
+
entry.is_mounted = 1;
entry.is_crc_checked = 1;
entry.fp_type = PHAR_TMP;
efree(entry.filename);
return FAILURE;
}
+
if (ssb.sb.st_mode & S_IFDIR) {
entry.is_dir = 1;
if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
entry.is_dir = 0;
entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
}
+
entry.flags = ssb.sb.st_mode;
+
if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
return SUCCESS;
}
+
efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
+/* }}} */
char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
{
#if PHP_VERSION_ID >= 50300
char *path, *fname, *arch, *entry, *ret, *test;
int arch_len, entry_len, fname_len;
+ phar_archive_data *phar;
if (pphar) {
*pphar = NULL;
+ } else {
+ pphar = &phar;
}
if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
+
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
+ if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && 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);
+ phar = PHAR_G(last_phar);
+ goto splitted;
+ }
+
if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
+
efree(entry);
+
if (*filename == '.') {
int try_len;
- if (SUCCESS != (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);
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
+splitted:
+ if (pphar) {
+ *pphar = phar;
+ }
+
try_len = filename_len;
test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
+
if (*test == '/') {
- if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) {
+ if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
spprintf(&ret, 0, "phar://%s%s", arch, test);
efree(arch);
efree(test);
return ret;
}
} else {
- if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) {
+ if (zend_hash_exists(&(phar->manifest), test, try_len)) {
spprintf(&ret, 0, "phar://%s/%s", arch, test);
efree(arch);
efree(test);
return ret;
}
}
+ efree(test);
}
+
spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
efree(arch);
ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
efree(path);
+
if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
char *arch;
int arch_len, ret_len;
if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return ret;
}
+
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+
+ if (!pphar && PHAR_G(manifest_cached)) {
+ zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+ }
+
efree(arch);
efree(entry);
}
+
return ret;
#else /* PHP 5.2 */
char resolved_path[MAXPATHLEN];
int n = 0;
char *fname, *arch, *entry, *ret, *test;
int arch_len, entry_len;
+ phar_archive_data *phar = NULL;
if (!filename) {
return NULL;
if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
goto doit;
}
+
fname = zend_get_executed_filename(TSRMLS_C);
+
if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
goto doit;
}
efree(entry);
+
if (*filename == '.') {
- phar_archive_data **pphar;
int try_len;
- if (SUCCESS != (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 doit;
}
+
try_len = filename_len;
test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
+
if (*test == '/') {
- if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) {
+ if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
spprintf(&ret, 0, "phar://%s%s", arch, test);
efree(arch);
efree(test);
return ret;
}
} else {
- if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) {
+ if (zend_hash_exists(&(phar->manifest), test, try_len)) {
spprintf(&ret, 0, "phar://%s/%s", arch, test);
efree(arch);
efree(test);
return ret;
}
}
+
efree(test);
}
- efree(arch);
+ efree(arch);
doit:
- if (*filename == '.' ||
- IS_ABSOLUTE_PATH(filename, filename_len) ||
- !path ||
- !*path) {
+ if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) {
if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
return estrdup(resolved_path);
} else {
return NULL;
}
}
+
/* test for stream wrappers and return */
for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
+
if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
/* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
return estrndup(filename, filename_len);
maybe_stream = 0;
goto not_stream;
}
+
for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
ptr = end + 1;
continue;
}
+
memcpy(trypath, ptr, end-ptr);
len = end-ptr;
trypath[end-ptr] = '/';
if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
break;
}
+
memcpy(trypath, ptr, len);
trypath[len] = '/';
memcpy(trypath+len+1, filename, filename_len+1);
if (wrapper == &php_stream_phar_wrapper) {
char *arch, *entry;
int arch_len, entry_len, ret_len;
-
+
ret_len = strlen(trypath);
/* found phar:// */
if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return estrndup(trypath, ret_len);
}
+
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+
+ if (!pphar && PHAR_G(manifest_cached)) {
+ zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+ }
+
efree(arch);
efree(entry);
+
return estrndup(trypath, ret_len);
}
return estrdup(trypath);
}
} /* end provided path */
- /* check in calling scripts' current working directory as a fall back case
- */
+ /* check in calling scripts' current working directory as a fall back case */
if (zend_is_executing(TSRMLS_C)) {
char *exec_fname = zend_get_executed_filename(TSRMLS_C);
int exec_fname_length = strlen(exec_fname);
int n = 0;
while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
- if (exec_fname && exec_fname[0] != '[' &&
- exec_fname_length > 0 &&
- exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
+ if (exec_fname && exec_fname[0] != '[' &&
+ exec_fname_length > 0 &&
+ exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
memcpy(trypath, exec_fname, exec_fname_length + 1);
memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
/* search for stream wrapper */
for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
+
if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
char *actual;
-
+
wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+
if (wrapper == &php_plain_files_wrapper) {
/* this should never technically happen, but we'll leave it here for completeness */
strncpy(trypath, actual, MAXPATHLEN);
} else if (!wrapper) {
- /* if wrapper is NULL, there was a mal-formed include_path stream wrapper
+ /* if wrapper is NULL, there was a malformed include_path stream wrapper
this also should be impossible */
return NULL;
} else {
return estrdup(trypath);
}
}
+
if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
return estrdup(resolved_path);
}
if (!ret) {
return FAILURE;
}
+
*ret = NULL;
+
if (error) {
*error = NULL;
}
+
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
return FAILURE;
}
+
if (for_write && PHAR_G(readonly) && !phar->is_data) {
if (error) {
spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
}
return FAILURE;
}
+
if (!path_len) {
if (error) {
spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
}
return FAILURE;
}
+really_get_entry:
if (allow_dir) {
if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
return FAILURE;
}
}
+
+ if (for_write && phar->is_persistent) {
+ if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
+ }
+ return FAILURE;
+ } else {
+ goto really_get_entry;
+ }
+ }
+
if (entry->is_modified && !for_write) {
if (error) {
spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
}
return FAILURE;
}
+
if (entry->fp_refcount && for_write) {
if (error) {
spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
}
return FAILURE;
}
+
if (entry->is_deleted) {
if (!for_create) {
return FAILURE;
}
entry->is_deleted = 0;
}
+
if (entry->is_dir) {
*ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
(*ret)->position = 0;
(*ret)->internal_file = entry;
(*ret)->is_zip = entry->is_zip;
(*ret)->is_tar = entry->is_tar;
- ++(entry->phar->refcount);
- ++(entry->fp_refcount);
+
+ if (!phar->is_persistent) {
+ ++(entry->phar->refcount);
+ ++(entry->fp_refcount);
+ }
+
return SUCCESS;
}
+
if (entry->fp_type == PHAR_MOD) {
if (for_trunc) {
if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
entry->link = NULL;
entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
}
+
if (for_write) {
if (for_trunc) {
if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
}
}
}
+
*ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
(*ret)->position = 0;
(*ret)->phar = phar;
(*ret)->is_zip = entry->is_zip;
(*ret)->is_tar = entry->is_tar;
(*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
- (*ret)->zero = entry->offset;
- ++(entry->fp_refcount);
- ++(entry->phar->refcount);
+ (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
+
+ if (!phar->is_persistent) {
+ ++(entry->fp_refcount);
+ ++(entry->phar->refcount);
+ }
+
return SUCCESS;
}
/* }}} */
return NULL;
}
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
+ }
+ return NULL;
+ }
+
/* create a new phar data holder */
ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
etemp.filename_len = path_len;
etemp.fp_type = PHAR_MOD;
etemp.fp = php_stream_fopen_tmpfile();
+
if (!etemp.fp) {
if (error) {
spprintf(error, 0, "phar error: unable to create temporary file");
}
+ efree(ret);
return NULL;
}
+
etemp.fp_refcount = 1;
if (allow_dir == 2) {
} else {
etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
}
+
+ phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
etemp.is_modified = 1;
etemp.timestamp = time(0);
etemp.is_crc_checked = 1;
etemp.phar = phar;
etemp.filename = estrndup(path, path_len);
etemp.is_zip = phar->is_zip;
+
if (phar->is_tar) {
etemp.is_tar = phar->is_tar;
etemp.tar_type = TAR_FILE;
}
+
if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
+ php_stream_close(etemp.fp);
if (error) {
spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
}
+ efree(ret);
+ efree(etemp.filename);
return NULL;
}
-
+
if (!entry) {
php_stream_close(etemp.fp);
efree(etemp.filename);
+ efree(ret);
return NULL;
}
ret->is_zip = entry->is_zip;
ret->is_tar = entry->is_tar;
ret->internal_file = entry;
+
return ret;
}
/* }}} */
/* initialize a phar_archive_data's read-only fp for existing phar data */
-int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC)
+int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
{
- if (phar->fp) {
+ if (phar_get_pharfp(phar TSRMLS_CC)) {
return SUCCESS;
}
-
#if PHP_MAJOR_VERSION < 6
if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
return FAILURE;
}
#endif
-
+
if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
return FAILURE;
}
- phar->fp = php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL);
- if (!phar->fp) {
+ phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
+
+ if (!phar_get_pharfp(phar TSRMLS_CC)) {
return FAILURE;
}
+
return SUCCESS;
}
+/* }}} */
/* copy file data from an existing to a new phar_entry_info that is not in the manifest */
-int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC)
+int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
{
phar_entry_info *link;
if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
return FAILURE;
}
+
if (dest->link) {
efree(dest->link);
dest->link = NULL;
dest->tar_type = (dest->tar_type ? TAR_FILE : 0);
}
+
dest->fp_type = PHAR_MOD;
dest->offset = 0;
dest->is_modified = 1;
dest->fp = php_stream_fopen_tmpfile();
-
phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
link = phar_get_link_source(source TSRMLS_CC);
+
if (!link) {
link = source;
}
+
if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize)) {
php_stream_close(dest->fp);
dest->fp_type = PHAR_FP;
}
return FAILURE;
}
+
return SUCCESS;
}
+/* }}} */
/* open and decompress a compressed phar entry
*/
-int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC)
+int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
{
php_stream_filter *filter;
phar_archive_data *phar = entry->phar;
char *filtername;
off_t loc;
+ php_stream *ufp;
if (follow_links && entry->link) {
phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
-
if (link_entry && link_entry != entry) {
return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
}
}
+
if (entry->fp_type == PHAR_TMP) {
if (!entry->fp) {
entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
}
return SUCCESS;
}
+
if (entry->fp_type != PHAR_FP) {
/* either newly created or already modified */
return SUCCESS;
}
- if (!phar->fp) {
+
+ if (!phar_get_pharfp(phar TSRMLS_CC)) {
if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
return FAILURE;
}
}
+
if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
return SUCCESS;
}
- if (!phar->ufp) {
- phar->ufp = php_stream_fopen_tmpfile();
- if (!phar->ufp) {
+
+ if (!phar_get_entrypufp(entry TSRMLS_CC)) {
+ phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
+ if (!phar_get_entrypufp(entry TSRMLS_CC)) {
spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
return FAILURE;
}
}
+ ufp = phar_get_entrypufp(entry TSRMLS_CC);
+
if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
- filter = php_stream_filter_create(filtername, NULL, php_stream_is_persistent(phar->ufp) TSRMLS_CC);
+ filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
} else {
filter = NULL;
}
+
if (!filter) {
spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
return FAILURE;
}
+
/* now we can safely use proper decompression */
/* save the new offset location within ufp */
- php_stream_seek(phar->ufp, 0, SEEK_END);
- loc = php_stream_tell(phar->ufp);
- php_stream_filter_append(&phar->ufp->writefilters, filter);
- php_stream_seek(phar->fp, entry->offset, SEEK_SET);
- if (php_stream_copy_to_stream(phar->fp, phar->ufp, entry->compressed_filesize) != entry->compressed_filesize) {
+ php_stream_seek(ufp, 0, SEEK_END);
+ loc = php_stream_tell(ufp);
+ php_stream_filter_append(&ufp->writefilters, filter);
+ php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
+
+ if (php_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize) != entry->compressed_filesize) {
spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
return FAILURE;
}
+
php_stream_filter_flush(filter, 1);
- php_stream_flush(phar->ufp);
+ php_stream_flush(ufp);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
- if (php_stream_tell(phar->ufp) - loc != (off_t) entry->uncompressed_filesize) {
+
+ if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
return FAILURE;
}
entry->old_flags = entry->flags;
- entry->fp_type = PHAR_UFP;
- /* this is now the new location of the file contents within this fp */
- entry->offset = loc;
+ /* this is now the new location of the file contents within this fp */
+ phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
return SUCCESS;
}
+/* }}} */
#if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
typedef struct {
entry->offset = 0;
return SUCCESS;
}
+
if (error) {
*error = NULL;
}
+
/* open a new temp file for writing */
if (entry->link) {
efree(entry->link);
entry->link = NULL;
entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
}
+
entry->fp = php_stream_fopen_tmpfile();
+
if (!entry->fp) {
if (error) {
spprintf(error, 0, "phar error: unable to create temporary file");
}
return FAILURE;
}
+
entry->old_flags = entry->flags;
entry->is_modified = 1;
phar->is_modified = 1;
}
/* }}} */
-int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC)
+int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
{
php_stream *fp;
phar_entry_info *link;
fp = php_stream_fopen_tmpfile();
phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
link = phar_get_link_source(entry TSRMLS_CC);
+
if (!link) {
link = entry;
}
+
if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
if (error) {
spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
entry->is_modified = 1;
return SUCCESS;
}
+/* }}} */
/**
* helper function to open an internal file's fp just-in-time
*/
-phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp,
- char **error, int for_write TSRMLS_DC)
+phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp, char **error, int for_write TSRMLS_DC) /* {{{ */
{
if (error) {
*error = NULL;
}
return entry;
}
+/* }}} */
int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
{
- if (phar->refcount) {
+ if (phar->refcount || phar->is_persistent) {
return FAILURE;
}
+
/* this archive has no open references, so emit an E_STRICT and remove it */
if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
return FAILURE;
}
+
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
return SUCCESS;
}
/* }}} */
phar_archive_data *fd, **fd_ptr;
char *my_realpath, *save;
int save_len;
+ ulong fhash, ahash;
phar_request_initialize(TSRMLS_C);
if (error) {
*error = NULL;
}
+
*archive = NULL;
+
+ if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
+ *archive = PHAR_G(last_phar);
+ if (alias && alias_len) {
+
+ if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
+ }
+ *archive = NULL;
+ return FAILURE;
+ }
+
+ if (PHAR_G(last_phar)->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len, (void**)&fd_ptr)) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
+ }
+
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
+ PHAR_G(last_alias) = alias;
+ PHAR_G(last_alias_len) = alias_len;
+ }
+
+ return SUCCESS;
+ }
+
+ if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
+ fd = PHAR_G(last_phar);
+ fd_ptr = &fd;
+ goto alias_success;
+ }
+
if (alias && alias_len) {
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
+ ahash = zend_inline_hash_func(alias, alias_len);
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
+alias_success:
if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
}
return FAILURE;
}
+
*archive = *fd_ptr;
+ fd = *fd_ptr;
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = alias;
+ PHAR_G(last_alias_len) = alias_len;
+
return SUCCESS;
}
+
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
+ goto alias_success;
+ }
}
+
+ fhash = zend_inline_hash_func(fname, fname_len);
my_realpath = NULL;
save = fname;
save_len = fname_len;
+
if (fname && fname_len) {
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
*archive = *fd_ptr;
fd = *fd_ptr;
+
if (alias && alias_len) {
if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
if (error) {
}
return FAILURE;
}
+
if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
}
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+
+ zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
}
+
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = fd->alias;
+ PHAR_G(last_alias_len) = fd->alias_len;
+
return SUCCESS;
}
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, (void**)&fd_ptr)) {
+
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
*archive = *fd_ptr;
+ fd = *fd_ptr;
+
+ /* this could be problematic - alias should never be different from manifest alias
+ for cached phars */
+ if (!fd->is_temporary_alias && alias && alias_len) {
+ if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
+ }
+ return FAILURE;
+ }
+ }
+
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = fd->alias;
+ PHAR_G(last_alias_len) = fd->alias_len;
+
+ return SUCCESS;
+ }
+
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
+ fd = *archive = *fd_ptr;
+
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = fd->alias;
+ PHAR_G(last_alias_len) = fd->alias_len;
+
+ return SUCCESS;
+ }
+
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
+ fd = *archive = *fd_ptr;
+
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = fd->alias;
+ PHAR_G(last_alias_len) = fd->alias_len;
+
return SUCCESS;
}
/* not found, try converting \ to / */
my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
+
if (my_realpath) {
fname_len = strlen(my_realpath);
fname = my_realpath;
#ifdef PHP_WIN32
phar_unixify_path_separators(fname, fname_len);
#endif
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ fhash = zend_inline_hash_func(fname, fname_len);
+
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
+realpath_success:
*archive = *fd_ptr;
fd = *fd_ptr;
+
if (alias && alias_len) {
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
}
+
efree(my_realpath);
+
+ PHAR_G(last_phar) = fd;
+ PHAR_G(last_phar_name) = fd->fname;
+ PHAR_G(last_phar_name_len) = fd->fname_len;
+ PHAR_G(last_alias) = fd->alias;
+ PHAR_G(last_alias_len) = fd->alias_len;
+
return SUCCESS;
}
+
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
+ goto realpath_success;
+ }
+
efree(my_realpath);
}
+
return FAILURE;
}
/* }}} */
} else {
flags = entry->flags;
}
+
switch (flags & PHAR_ENT_COMPRESSION_MASK) {
- case PHAR_ENT_COMPRESSED_GZ:
- return "zlib.inflate";
- case PHAR_ENT_COMPRESSED_BZ2:
- return "bzip2.decompress";
- default:
- return return_unknown ? "unknown" : NULL;
+ case PHAR_ENT_COMPRESSED_GZ:
+ return "zlib.inflate";
+ case PHAR_ENT_COMPRESSED_BZ2:
+ return "bzip2.decompress";
+ default:
+ return return_unknown ? "unknown" : NULL;
}
}
/* }}} */
}
return NULL;
}
+
if (!path_len && !dir) {
if (error) {
spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
}
return NULL;
}
+
if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
if (error) {
spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
return NULL;
}
return entry;
- } else if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
+ }
+
+ if (dir) {
+ if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
+ /* a file or directory exists in a sub-directory of this path */
+ entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
+ /* this next line tells PharFileInfo->__destruct() to efree the filename */
+ entry->is_temp_dir = entry->is_dir = 1;
+ entry->filename = (char *) estrndup(path, path_len + 1);
+ entry->filename_len = path_len;
+ entry->phar = phar;
+ return entry;
+ }
+ }
+
+ if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
phar_zstr key;
char *str_key;
ulong unused;
}
return NULL;
}
+
if (!entry->tmp || !entry->is_mounted) {
if (error) {
spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
}
return NULL;
}
+
test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
+
if (SUCCESS != php_stream_stat_path(test, &ssb)) {
efree(test);
return NULL;
}
+
if (ssb.sb.st_mode & S_IFDIR && !dir) {
efree(test);
if (error) {
}
return NULL;
}
+
if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
efree(test);
/* user requested a directory, we must return one */
}
return NULL;
}
+
/* mount the file just in time */
if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
efree(test);
}
return NULL;
}
+
efree(test);
+
if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
if (error) {
spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
}
}
}
- if (dir) {
- /* try to find a directory */
- HashTable *manifest;
- phar_zstr key;
- char *str_key;
- uint keylen;
- ulong unused;
- if (!path_len) {
- path = "/";
- }
- manifest = &phar->manifest;
- 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;
- }
+ return NULL;
+}
+/* }}} */
- PHAR_STR(key, str_key);
+static const char hexChars[] = "0123456789ABCDEF";
- if (0 != memcmp(str_key, path, path_len)) {
- /* entry in directory not found */
- if (SUCCESS != zend_hash_move_forward(manifest)) {
- break;
- }
- continue;
- } else {
- if (str_key[path_len] != '/') {
- if (SUCCESS != zend_hash_move_forward(manifest)) {
- break;
- }
- continue;
- }
- /* found a file in this path */
- entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
- /* this next line tells PharFileInfo->__destruct() to efree the filename */
- entry->is_temp_dir = entry->is_dir = 1;
- entry->filename = (char *) estrndup(path, path_len + 1);
- entry->filename_len = path_len;
- entry->phar = phar;
- return entry;
- }
- }
+static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
+{
+ int pos = -1;
+ size_t len = 0;
+
+ *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
+
+ for (; len < digest_len; ++len) {
+ (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
+ (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
}
- return NULL;
+ (*signature)[++pos] = '\0';
+ return pos;
}
/* }}} */
+
+#ifndef PHAR_HAVE_OPENSSL
+static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
+
+ MAKE_STD_ZVAL(zdata);
+ MAKE_STD_ZVAL(openssl);
+ ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
+ MAKE_STD_ZVAL(zsig);
+ ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
+ MAKE_STD_ZVAL(zkey);
+ ZVAL_STRINGL(zkey, key, key_len, 1);
+ zp[0] = &zdata;
+ zp[1] = &zsig;
+ zp[2] = &zkey;
+
+ php_stream_rewind(fp);
+ Z_TYPE_P(zdata) = IS_STRING;
+ Z_STRLEN_P(zdata) = end;
+
+ if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ return FAILURE;
+ }
+#if PHP_VERSION_ID < 50300
+ if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
+#else
+ if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
+#endif
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ zval_dtor(openssl);
+ efree(openssl);
+ return FAILURE;
+ }
+
+ fci.param_count = 3;
+ fci.params = zp;
+#if PHP_VERSION_ID < 50300
+ ++(zdata->refcount);
+ ++(zsig->refcount);
+ ++(zkey->refcount);
+#else
+ Z_ADDREF_P(zdata);
+ if (is_sign) {
+ Z_SET_ISREF_P(zsig);
+ } else {
+ Z_ADDREF_P(zsig);
+ }
+ Z_ADDREF_P(zkey);
+#endif
+ fci.retval_ptr_ptr = &retval_ptr;
+
+ if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
+ zval_dtor(zdata);
+ zval_dtor(zsig);
+ zval_dtor(zkey);
+ zval_dtor(openssl);
+ efree(openssl);
+ efree(zdata);
+ efree(zkey);
+ efree(zsig);
+ return FAILURE;
+ }
+
+ zval_dtor(openssl);
+ efree(openssl);
+#if PHP_VERSION_ID < 50300
+ --(zdata->refcount);
+ --(zsig->refcount);
+ --(zkey->refcount);
+#else
+ Z_DELREF_P(zdata);
+ if (is_sign) {
+ Z_UNSET_ISREF_P(zsig);
+ } else {
+ Z_DELREF_P(zsig);
+ }
+ Z_DELREF_P(zkey);
+#endif
+ zval_dtor(zdata);
+ efree(zdata);
+ zval_dtor(zkey);
+ efree(zkey);
+
+ switch (Z_TYPE_P(retval_ptr)) {
+ default:
+ case IS_LONG:
+ zval_dtor(zsig);
+ efree(zsig);
+ if (1 == Z_LVAL_P(retval_ptr)) {
+ efree(retval_ptr);
+ return SUCCESS;
+ }
+ efree(retval_ptr);
+ return FAILURE;
+ case IS_BOOL:
+ efree(retval_ptr);
+ if (Z_BVAL_P(retval_ptr)) {
+ *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
+ *signature_len = Z_STRLEN_P(zsig);
+ zval_dtor(zsig);
+ efree(zsig);
+ return SUCCESS;
+ }
+ zval_dtor(zsig);
+ efree(zsig);
+ return FAILURE;
+ }
+}
+/* }}} */
+#endif /* #ifndef PHAR_HAVE_OPENSSL */
+
+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 read_size, len;
+ off_t read_len;
+ unsigned char buf[1024];
+
+ php_stream_rewind(fp);
+
+ switch (sig_type) {
+ case PHAR_SIG_OPENSSL: {
+#ifdef PHAR_HAVE_OPENSSL
+ BIO *in;
+ EVP_PKEY *key;
+ EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
+ EVP_MD_CTX md_ctx;
+#else
+ int tempsig;
+#endif
+ php_uint32 pubkey_len;
+ char *pubkey = NULL, *pfile;
+ php_stream *pfp;
+#ifndef PHAR_HAVE_OPENSSL
+ if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
+ if (error) {
+ spprintf(error, 0, "openssl not loaded");
+ }
+ return FAILURE;
+ }
+#endif
+ /* use __FILE__ . '.pubkey' for public key file */
+ spprintf(&pfile, 0, "%s.pubkey", fname);
+ pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
+ efree(pfile);
+
+ if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
+ if (error) {
+ spprintf(error, 0, "openssl public key could not be read");
+ }
+ return FAILURE;
+ }
+
+ php_stream_close(pfp);
+#ifndef PHAR_HAVE_OPENSSL
+ tempsig = sig_len;
+
+ if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
+ if (pubkey) {
+ efree(pubkey);
+ }
+
+ if (error) {
+ spprintf(error, 0, "openssl signature could not be verified");
+ }
+
+ return FAILURE;
+ }
+
+ if (pubkey) {
+ efree(pubkey);
+ }
+
+ sig_len = tempsig;
+#else
+ in = BIO_new_mem_buf(pubkey, pubkey_len);
+
+ if (NULL == in) {
+ efree(pubkey);
+ if (error) {
+ spprintf(error, 0, "openssl signature could not be processed");
+ }
+ return FAILURE;
+ }
+
+ key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
+ BIO_free(in);
+ efree(pubkey);
+
+ if (NULL == key) {
+ if (error) {
+ spprintf(error, 0, "openssl signature could not be processed");
+ }
+ return FAILURE;
+ }
+
+ EVP_VerifyInit(&md_ctx, mdtype);
+ read_len = end_of_phar;
+
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+
+ php_stream_seek(fp, 0, SEEK_SET);
+
+ while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ EVP_VerifyUpdate (&md_ctx, buf, len);
+ read_len -= (off_t)len;
+
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+
+ if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
+ /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
+ EVP_MD_CTX_cleanup(&md_ctx);
+
+ if (error) {
+ spprintf(error, 0, "broken openssl signature");
+ }
+
+ return FAILURE;
+ }
+
+ EVP_MD_CTX_cleanup(&md_ctx);
+#endif
+
+ *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
+ }
+ break;
+#if HAVE_HASH_EXT
+ case PHAR_SIG_SHA512: {
+ unsigned char digest[64];
+ PHP_SHA512_CTX context;
+
+ PHP_SHA512Init(&context);
+ read_len = end_of_phar;
+
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA512Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+
+ PHP_SHA512Final(digest, &context);
+
+ if (memcmp(digest, sig, sizeof(digest))) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
+ *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
+ break;
+ }
+ case PHAR_SIG_SHA256: {
+ unsigned char digest[32];
+ PHP_SHA256_CTX context;
+
+ PHP_SHA256Init(&context);
+ read_len = end_of_phar;
+
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA256Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+
+ PHP_SHA256Final(digest, &context);
+
+ if (memcmp(digest, sig, sizeof(digest))) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
+ *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
+ break;
+ }
+#else
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
+ if (error) {
+ spprintf(error, 0, "unsupported signature");
+ }
+ return FAILURE;
+#endif
+ case PHAR_SIG_SHA1: {
+ unsigned char digest[20];
+ PHP_SHA1_CTX context;
+
+ PHP_SHA1Init(&context);
+ read_len = end_of_phar;
+
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA1Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+
+ PHP_SHA1Final(digest, &context);
+
+ if (memcmp(digest, sig, sizeof(digest))) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
+ *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
+ break;
+ }
+ case PHAR_SIG_MD5: {
+ unsigned char digest[16];
+ PHP_MD5_CTX context;
+
+ PHP_MD5Init(&context);
+ read_len = end_of_phar;
+
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_MD5Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+
+ PHP_MD5Final(digest, &context);
+
+ if (memcmp(digest, sig, sizeof(digest))) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
+ *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
+ break;
+ }
+ default:
+ if (error) {
+ spprintf(error, 0, "broken or unsupported signature");
+ }
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
+{
+ unsigned char buf[1024];
+ int sig_len;
+
+ php_stream_rewind(fp);
+
+ if (phar->signature) {
+ efree(phar->signature);
+ phar->signature = NULL;
+ }
+
+ switch(phar->sig_flags) {
+#if HAVE_HASH_EXT
+ case PHAR_SIG_SHA512: {
+ unsigned char digest[64];
+ PHP_SHA512_CTX context;
+
+ PHP_SHA512Init(&context);
+
+ while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA512Update(&context, buf, sig_len);
+ }
+
+ PHP_SHA512Final(digest, &context);
+ *signature = estrndup((char *) digest, 64);
+ *signature_length = 64;
+ break;
+ }
+ case PHAR_SIG_SHA256: {
+ unsigned char digest[32];
+ PHP_SHA256_CTX context;
+
+ PHP_SHA256Init(&context);
+
+ while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA256Update(&context, buf, sig_len);
+ }
+
+ PHP_SHA256Final(digest, &context);
+ *signature = estrndup((char *) digest, 32);
+ *signature_length = 32;
+ break;
+ }
+#else
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
+ if (error) {
+ spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
+ }
+
+ return FAILURE;
+#endif
+ case PHAR_SIG_OPENSSL: {
+ int siglen;
+ unsigned char *sigbuf;
+#ifdef PHAR_HAVE_OPENSSL
+ BIO *in;
+ EVP_PKEY *key;
+ EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
+ EVP_MD_CTX md_ctx;
+
+ in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
+
+ if (in == NULL) {
+ if (error) {
+ spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
+ }
+ return FAILURE;
+ }
+
+ key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
+ BIO_free(in);
+
+ if (!key) {
+ if (error) {
+ spprintf(error, 0, "unable to process private key");
+ }
+ return FAILURE;
+ }
+
+ siglen = EVP_PKEY_size(key);
+ sigbuf = emalloc(siglen + 1);
+ EVP_SignInit(&md_ctx, mdtype);
+
+ while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
+ EVP_SignUpdate(&md_ctx, buf, sig_len);
+ }
+
+ if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
+ efree(sigbuf);
+ if (error) {
+ spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
+ }
+ return FAILURE;
+ }
+
+ sigbuf[siglen] = '\0';
+ EVP_MD_CTX_cleanup(&md_ctx);
+#else
+ sigbuf = NULL;
+ siglen = 0;
+ php_stream_seek(fp, 0, SEEK_END);
+
+ if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
+ }
+ return FAILURE;
+ }
+#endif
+ *signature = (char *) sigbuf;
+ *signature_length = siglen;
+ }
+ break;
+ default:
+ phar->sig_flags = PHAR_SIG_SHA1;
+ case PHAR_SIG_SHA1: {
+ unsigned char digest[20];
+ PHP_SHA1_CTX context;
+
+ PHP_SHA1Init(&context);
+
+ while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA1Update(&context, buf, sig_len);
+ }
+
+ PHP_SHA1Final(digest, &context);
+ *signature = estrndup((char *) digest, 20);
+ *signature_length = 20;
+ break;
+ }
+ case PHAR_SIG_MD5: {
+ unsigned char digest[16];
+ PHP_MD5_CTX context;
+
+ PHP_MD5Init(&context);
+
+ while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
+ PHP_MD5Update(&context, buf, sig_len);
+ }
+
+ PHP_MD5Final(digest, &context);
+ *signature = estrndup((char *) digest, 16);
+ *signature_length = 16;
+ break;
+ }
+ }
+
+ phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
+ return SUCCESS;
+}
+/* }}} */
+
+void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
+{
+ char *s;
+
+ while ((s = zend_memrchr(filename, '/', filename_len))) {
+ filename_len = s - filename;
+ if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
+ break;
+ }
+ }
+}
+/* }}} */
+
+static void phar_update_cached_entry(void *data, void *argument) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *)data;
+ TSRMLS_FETCH();
+
+ entry->phar = (phar_archive_data *)argument;
+
+ if (entry->link) {
+ entry->link = estrdup(entry->link);
+ }
+
+ if (entry->tmp) {
+ entry->tmp = estrdup(entry->tmp);
+ }
+
+ entry->metadata_str.c = 0;
+ entry->filename = estrndup(entry->filename, entry->filename_len);
+ entry->is_persistent = 0;
+
+ if (entry->metadata) {
+ if (entry->metadata_len) {
+ /* assume success, we would have failed before */
+ phar_parse_metadata((char **) &entry->metadata, &entry->metadata, entry->metadata_len TSRMLS_CC);
+ } else {
+ zval *t;
+
+ t = entry->metadata;
+ ALLOC_ZVAL(entry->metadata);
+ *entry->metadata = *t;
+ zval_copy_ctor(entry->metadata);
+#if PHP_VERSION_ID < 50300
+ entry->metadata->refcount = 1;
+#else
+ Z_SET_REFCOUNT_P(entry->metadata, 1);
+#endif
+ entry->metadata_str.c = NULL;
+ entry->metadata_str.len = 0;
+ }
+ }
+}
+/* }}} */
+
+static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ HashTable newmanifest;
+ char *fname;
+
+ phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
+ *phar = **pphar;
+ phar->is_persistent = 0;
+ fname = phar->fname;
+ phar->fname = estrndup(phar->fname, phar->fname_len);
+ phar->ext = phar->fname + (phar->ext - fname);
+
+ if (phar->alias) {
+ phar->alias = estrndup(phar->alias, phar->alias_len);
+ }
+
+ if (phar->signature) {
+ phar->signature = estrdup(phar->signature);
+ }
+
+ if (phar->metadata) {
+ /* assume success, we would have failed before */
+ if (phar->metadata_len) {
+ phar_parse_metadata((char **) &phar->metadata, &phar->metadata, phar->metadata_len TSRMLS_CC);
+ } else {
+ zval *t;
+
+ t = phar->metadata;
+ ALLOC_ZVAL(phar->metadata);
+ *phar->metadata = *t;
+ zval_copy_ctor(phar->metadata);
+#if PHP_VERSION_ID < 50300
+ phar->metadata->refcount = 1;
+#else
+ Z_SET_REFCOUNT_P(phar->metadata, 1);
+#endif
+ }
+ }
+
+ zend_hash_init(&newmanifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
+ zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
+ phar->manifest = newmanifest;
+ zend_hash_init(&phar->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ zend_hash_init(&phar->virtual_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
+ *pphar = phar;
+}
+/* }}} */
+
+int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data **newpphar, *newphar = NULL;
+
+ if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
+ return FAILURE;
+ }
+
+ *newpphar = *pphar;
+ phar_copy_cached_phar(newpphar TSRMLS_CC);
+ /* invalidate phar cache */
+ PHAR_G(last_phar) = NULL;
+ PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
+ if (newpphar[0]->alias_len && FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), newpphar[0]->alias, newpphar[0]->alias_len, (void*)newpphar, sizeof(phar_archive_data*), NULL)) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
+ return FAILURE;
+ }
+
+ *pphar = *newpphar;
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * 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
+ */
# 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;
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
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
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);
- 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;
+ tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
+ tm->tm_mon = ((ddate>>5)&15) - 1;
+ tm->tm_mday = ddate&31;
- tm->tm_hour = (dtime>>11)&31;
- tm->tm_min = (dtime>>5)&63;
- tm->tm_sec = (dtime<<1)&62;
+ tm->tm_hour = (dtime>>11)&31;
+ tm->tm_min = (dtime>>5)&63;
+ tm->tm_sec = (dtime<<1)&62;
- return mktime(tm);
+ 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
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;
} else {
php_stream_seek(fp, 0, SEEK_SET);
}
+
if (!(read = php_stream_read(fp, buf, size))) {
php_stream_close(fp);
if (error) {
}
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));
}
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);
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) {
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); \
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);
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--;
} 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 */
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");
}
}
/* 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)) {
}
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;
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) {
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;
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;
}
/* }}} */
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;
}
/* }}} */
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;
return ZEND_HASH_APPLY_KEEP;
}
}
+
memset(&local, 0, sizeof(local));
memset(¢ral, 0, sizeof(central));
memset(&perms, 0, sizeof(perms));
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;
}
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);
/* 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);
} 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;
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 *)¢ral, 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;
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) {
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;
}
/* }}} */
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;
}
/* 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);
} 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)) {
}
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);
} else {
free_user_stub = 0;
}
+
if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
{
if (error) {
}
return EOF;
}
+
len = pos - user_stub + 18;
entry.fp = php_stream_fopen_tmpfile();
entry.uncompressed_filesize = len + 5;
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);
}
return EOF;
}
+
if (free_user_stub) {
efree(user_stub);
}
}
}
}
-
nostub:
-
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
/* save modified files to the zip */
pass.old = oldfile;
pass.filefp = php_stream_fopen_tmpfile();
+
if (!pass.filefp) {
if (closeoldfile) {
php_stream_close(oldfile);
}
return EOF;
}
+
pass.centralfp = php_stream_fopen_tmpfile();
+
if (!pass.centralfp) {
if (closeoldfile) {
php_stream_close(oldfile);
}
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);
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);
}
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) {
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) {
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);
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;
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
+ */