summaryrefslogtreecommitdiff
path: root/main/streams/streams.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/streams/streams.c')
-rw-r--r--main/streams/streams.c103
1 files changed, 89 insertions, 14 deletions
diff --git a/main/streams/streams.c b/main/streams/streams.c
index dfd60940fc..e9c2e07320 100644
--- a/main/streams/streams.c
+++ b/main/streams/streams.c
@@ -105,6 +105,15 @@ PHP_RSHUTDOWN_FUNCTION(streams)
return SUCCESS;
}
+PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed)
+{
+ php_stream *orig = enclosed->enclosing_stream;
+
+ php_stream_auto_cleanup(enclosed);
+ enclosed->enclosing_stream = enclosing;
+ return orig;
+}
+
PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC)
{
zend_rsrc_list_entry *le;
@@ -324,19 +333,56 @@ fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persiste
ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream);
strlcpy(ret->mode, mode, sizeof(ret->mode));
+ ret->wrapper = NULL;
+ ret->wrapperthis = NULL;
+ ret->wrapperdata = NULL;
+ ret->stdiocast = NULL;
+ ret->orig_path = NULL;
+ ret->context = NULL;
+ ret->readbuf = NULL;
+ ret->enclosing_stream = NULL;
+
return ret;
}
/* }}} */
+PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC) /* {{{ */
+{
+ return _php_stream_free(stream_enclosed,
+ close_options | PHP_STREAM_FREE_IGNORE_ENCLOSING TSRMLS_CC);
+}
+/* }}} */
+
+#if STREAM_DEBUG
+static const char *_php_stream_pretty_free_options(int close_options, char *out)
+{
+ if (close_options & PHP_STREAM_FREE_CALL_DTOR)
+ strcat(out, "CALL_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_RELEASE_STREAM)
+ strcat(out, "RELEASE_STREAM, ");
+ if (close_options & PHP_STREAM_FREE_PRESERVE_HANDLE)
+ strcat(out, "PREVERSE_HANDLE, ");
+ if (close_options & PHP_STREAM_FREE_RSRC_DTOR)
+ strcat(out, "RSRC_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_PERSISTENT)
+ strcat(out, "PERSISTENT, ");
+ if (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING)
+ strcat(out, "IGNORE_ENCLOSING, ");
+ if (out[0] != '\0')
+ out[strlen(out) - 2] = '\0';
+ return out;
+}
+#endif
+
static int _php_stream_free_persistent(zend_rsrc_list_entry *le, void *pStream TSRMLS_DC)
{
return le->ptr == pStream;
}
+
PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */
{
int ret = 1;
- int remove_rsrc = 1;
int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
int release_cast = 1;
php_stream_context *context = NULL;
@@ -353,16 +399,40 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
}
#if STREAM_DEBUG
-fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->label, stream, stream->orig_path, stream->in_free, close_options);
+ {
+ char out[200] = "";
+ fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%s\n",
+ stream->ops->label, stream, stream->orig_path, stream->in_free, _php_stream_pretty_free_options(close_options, out));
+ }
+
#endif
- /* recursion protection */
if (stream->in_free) {
- return 1;
+ /* hopefully called recursively from the enclosing stream; the pointer was NULLed below */
+ if ((stream->in_free == 1) && (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) && (stream->enclosing_stream == NULL)) {
+ close_options |= PHP_STREAM_FREE_RSRC_DTOR; /* restore flag */
+ } else {
+ return 1; /* recursion protection */
+ }
}
stream->in_free++;
+ /* force correct order on enclosing/enclosed stream destruction (only from resource
+ * destructor as in when reverse destroying the resource list) */
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) &&
+ !(close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) &&
+ (close_options & (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)) && /* always? */
+ (stream->enclosing_stream != NULL)) {
+ php_stream *enclosing_stream = stream->enclosing_stream;
+ stream->enclosing_stream = NULL;
+ /* we force PHP_STREAM_CALL_DTOR because that's from where the
+ * enclosing stream can free this stream. We remove rsrc_dtor because
+ * we want the enclosing stream to be deleted from the resource list */
+ return _php_stream_free(enclosing_stream,
+ (close_options | PHP_STREAM_FREE_CALL_DTOR) & ~PHP_STREAM_FREE_RSRC_DTOR TSRMLS_CC);
+ }
+
/* if we are releasing the stream only (and preserving the underlying handle),
* we need to do things a little differently.
* We are only ever called like this when the stream is cast to a FILE*
@@ -383,14 +453,15 @@ fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->la
#if STREAM_DEBUG
fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n",
- stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast, remove_rsrc);
+ stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast,
+ (close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0);
#endif
/* make sure everything is saved */
_php_stream_flush(stream, 1 TSRMLS_CC);
/* If not called from the resource dtor, remove the stream from the resource list. */
- if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0 && remove_rsrc) {
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
/* zend_list_delete actually only decreases the refcount; if we're
* releasing the stream, we want to actually delete the resource from
* the resource list, otherwise the resource will point to invalid memory.
@@ -1410,7 +1481,7 @@ PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen
}
/* Returns SUCCESS/FAILURE and sets *len to the number of bytes moved */
-PHPAPI size_t _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
{
char buf[CHUNK_SIZE];
size_t readchunk;
@@ -1811,7 +1882,7 @@ PHPAPI int _php_stream_mkdir(char *path, int mode, int options, php_stream_conte
{
php_stream_wrapper *wrapper = NULL;
- wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
if (!wrapper || !wrapper->wops || !wrapper->wops->stream_mkdir) {
return 0;
}
@@ -1826,7 +1897,7 @@ PHPAPI int _php_stream_rmdir(char *path, int options, php_stream_context *contex
{
php_stream_wrapper *wrapper = NULL;
- wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
if (!wrapper || !wrapper->wops || !wrapper->wops->stream_rmdir) {
return 0;
}
@@ -1855,7 +1926,7 @@ PHPAPI int _php_stream_stat_path(char *path, int flags, php_stream_statbuf *ssb,
}
}
- wrapper = php_stream_locate_url_wrapper(path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, &path_to_open, 0 TSRMLS_CC);
if (wrapper && wrapper->wops->url_stat) {
ret = wrapper->wops->url_stat(wrapper, path_to_open, flags, ssb, context TSRMLS_CC);
if (ret == 0) {
@@ -1940,7 +2011,6 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
char *resolved_path = NULL;
char *copy_of_path = NULL;
-
if (opened_path) {
*opened_path = NULL;
}
@@ -2117,7 +2187,7 @@ PHPAPI void php_stream_context_free(php_stream_context *context)
efree(context);
}
-PHPAPI php_stream_context *php_stream_context_alloc(void)
+PHPAPI php_stream_context *php_stream_context_alloc(TSRMLS_D)
{
php_stream_context *context;
@@ -2126,7 +2196,7 @@ PHPAPI php_stream_context *php_stream_context_alloc(void)
MAKE_STD_ZVAL(context->options);
array_init(context->options);
- context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context());
+ context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context(TSRMLS_C));
return context;
}
@@ -2269,7 +2339,7 @@ PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_
return FAILURE;
}
- stream = php_stream_opendir(dirname, ENFORCE_SAFE_MODE | REPORT_ERRORS, context);
+ stream = php_stream_opendir(dirname, REPORT_ERRORS, context);
if (!stream) {
return FAILURE;
}
@@ -2292,6 +2362,11 @@ PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_
vector[nfiles] = estrdup(sdp.d_name);
nfiles++;
+ if(vector_size < 10 || nfiles == 0) {
+ /* overflow */
+ efree(vector);
+ return FAILURE;
+ }
}
php_stream_closedir(stream);