diff options
Diffstat (limited to 'main/streams/streams.c')
-rw-r--r-- | main/streams/streams.c | 103 |
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); |