From 7990d742e5fc32d5b1c9c49b7aab2e41acd75d0f Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Tue, 19 Mar 2002 23:29:37 +0000 Subject: [PATCH] Improve behaviour of the stream casting operation. Improve interaction with fopencookie. --- main/main.c | 14 +------- main/memory_streams.c | 46 +++++++++++++++++++++--- main/php_streams.h | 5 +++ main/streams.c | 81 +++++++++++++++++++++++++++++++++---------- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/main/main.c b/main/main.c index e6b8c8f0fd..1601b2b493 100644 --- a/main/main.c +++ b/main/main.c @@ -564,26 +564,14 @@ PHP_FUNCTION(set_time_limit) static FILE *php_fopen_wrapper_for_zend(const char *filename, char **opened_path) { FILE *retval = NULL; - php_stream *stream; size_t old_chunk_size; TSRMLS_FETCH(); old_chunk_size = FG(def_chunk_size); FG(def_chunk_size) = 1; - stream = php_stream_open_wrapper((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, opened_path); + retval = php_stream_open_wrapper_as_file((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, opened_path); FG(def_chunk_size) = old_chunk_size; - if (stream) { - /* when this succeeds, stream either has or will be freed automatically */ - if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE, - (void**)&retval, REPORT_ERRORS) == FAILURE) - { - php_stream_close(stream); - if (opened_path && *opened_path) - efree(*opened_path); - retval = NULL; - } - } return retval; } /* }}} */ diff --git a/main/memory_streams.c b/main/memory_streams.c index 579bd26cad..702e96f396 100644 --- a/main/memory_streams.c +++ b/main/memory_streams.c @@ -291,6 +291,7 @@ PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length ST } /* }}} */ +/* }}} */ /* {{{ ------- TEMP stream implementation -------*/ @@ -344,12 +345,17 @@ static size_t php_stream_temp_read(php_stream *stream, char *buf, size_t count T static int php_stream_temp_close(php_stream *stream, int close_handle TSRMLS_DC) { php_stream_temp_data *ts; + int ret; assert(stream != NULL); ts = stream->abstract; assert(ts != NULL); - return php_stream_close(ts->innerstream); + ret = php_stream_free(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE)); + + efree(ts); + + return ret; } /* }}} */ @@ -400,12 +406,44 @@ char *php_stream_temp_gets(php_stream *stream, char *buf, size_t maxlen TSRMLS_D static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) { php_stream_temp_data *ts; + php_stream *file; + size_t memsize; + char *membuf; + off_t pos; assert(stream != NULL); ts = stream->abstract; assert(ts != NULL); - return php_stream_cast(ts->innerstream, castas, ret, 0); + if (php_stream_is(ts->innerstream, PHP_STREAM_IS_STDIO)) { + return php_stream_cast(ts->innerstream, castas, ret, 0); + } + + /* we are still using a memory based backing. If they are if we can be + * a FILE*, say yes because we can perform the conversion. + * If they actually want to perform the conversion, we need to switch + * the memory stream to a tmpfile stream */ + + if (ret == NULL && castas == PHP_STREAM_AS_STDIO) { + return SUCCESS; + } + + /* say "no" to other stream forms */ + if (ret == NULL) { + return FAILURE; + } + + /* perform the conversion and then pass the request on to the innerstream */ + membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize); + file = php_stream_fopen_tmpfile(); + php_stream_write(file, membuf, memsize); + pos = php_stream_tell(ts->innerstream); + + php_stream_close(ts->innerstream); + ts->innerstream = file; + php_stream_seek(ts->innerstream, pos, SEEK_SET); + + return php_stream_cast(ts->innerstream, castas, ret, 1); } /* }}} */ @@ -425,13 +463,13 @@ PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STR php_stream_temp_data *self; php_stream *stream; - self = emalloc(sizeof(*self)); + self = ecalloc(1, sizeof(*self)); assert(self != NULL); self->smax = max_memory_usage; self->mode = mode; stream = php_stream_alloc(&php_stream_temp_ops, self, 0, "rwb"); self->innerstream = php_stream_memory_create(mode); - php_stream_temp_write(stream, NULL, 0 TSRMLS_CC); +// php_stream_temp_write(stream, NULL, 0 TSRMLS_CC); return stream; } /* }}} */ diff --git a/main/php_streams.h b/main/php_streams.h index a590c9c94f..98a62286f8 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -271,6 +271,11 @@ PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options, PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC); #define php_stream_make_seekable(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_CC TSRMLS_CC) +/* This is a utility API for extensions that are opening a stream, converting it + * to a FILE* and then closing it again. Be warned that fileno() on the result + * will most likely fail on systems with fopencookie. */ +PHPAPI FILE * _php_stream_open_wrapper_as_file(char * path, char * mode, int options, char **opened_path STREAMS_DC TSRMLS_DC); +#define php_stream_open_wrapper_as_file(path, mode, options, opened_path) _php_stream_open_wrapper_as_file((path), (mode), (options), (opened_path) STREAMS_CC TSRMLS_CC) /* for user-space streams */ extern php_stream_ops php_stream_userspace_ops; diff --git a/main/streams.c b/main/streams.c index 9665d8e240..687535e4b9 100755 --- a/main/streams.c +++ b/main/streams.c @@ -42,8 +42,8 @@ #include "build-defs.h" #endif +/* {{{ some macros to help track leaks */ #if ZEND_DEBUG -/* some macros to help track leaks */ #define emalloc_rel_orig(size) \ ( __php_stream_call_depth == 0 \ ? _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_RELAY_CC) \ @@ -62,6 +62,7 @@ # define perealloc_rel_orig(ptr, size, persistent) perealloc((ptr), (size), (persistent)) # define emalloc_rel_orig(size) emalloc((size)) #endif +/* }}} */ static HashTable url_stream_wrappers_hash; @@ -217,6 +218,9 @@ PHPAPI int _php_stream_flush(php_stream *stream TSRMLS_DC) PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) { + assert(stream); + if (buf == NULL || count == 0) + return 0; return stream->ops->write(stream, buf, count TSRMLS_CC); } @@ -381,6 +385,7 @@ PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size readchunk = maxlen - haveread; didread = php_stream_read(src, buf, readchunk); + if (didread) { /* extra paranoid */ size_t didwrite, towrite; @@ -392,7 +397,6 @@ PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size while(towrite) { didwrite = php_stream_write(dest, writeptr, towrite); - if (didwrite == 0) return 0; /* error */ @@ -400,7 +404,7 @@ PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size writeptr += didwrite; } } else { - if ( !maxlen) { + if (maxlen == 0) { return haveread; } else { return 0; /* error */ @@ -411,14 +415,11 @@ PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size break; } } - return haveread; } /* }}} */ - - /* {{{ ------- STDIO stream implementation -------*/ typedef struct { @@ -770,23 +771,31 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha #if HAVE_FOPENCOOKIE static ssize_t stream_cookie_reader(void *cookie, char *buffer, size_t size) { + ssize_t ret; TSRMLS_FETCH(); - return php_stream_read(((php_stream *)cookie), buffer, size); + + ret = php_stream_read(((php_stream *)cookie), buffer, size); + return ret; } -static ssize_t stream_cookie_writer(void *cookie, const char *buffer, size_t size) { +static ssize_t stream_cookie_writer(void *cookie, const char *buffer, size_t size) +{ TSRMLS_FETCH(); return php_stream_write(((php_stream *)cookie), (char *)buffer, size); } -static int stream_cookie_seeker(void *cookie, off_t position, int whence) { +static int stream_cookie_seeker(void *cookie, off_t position, int whence) +{ TSRMLS_FETCH(); - return php_stream_seek(((php_stream *)cookie), position, whence); + + return php_stream_seek((php_stream *)cookie, position, whence); } -static int stream_cookie_closer(void *cookie) { +static int stream_cookie_closer(void *cookie) +{ php_stream *stream = (php_stream*)cookie; TSRMLS_FETCH(); + /* prevent recursion */ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE; return php_stream_close(stream); @@ -815,10 +824,15 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show goto exit_success; } - if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) + /* if the stream is a stdio stream let's give it a chance to respond + * first, to avoid doubling up the layers of stdio with an fopencookie */ + if (php_stream_is(stream, PHP_STREAM_IS_STDIO) && + stream->ops->cast && + stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) + { goto exit_success; - - + } + #if HAVE_FOPENCOOKIE /* if just checking, say yes we can be a FILE*, but don't actually create it yet */ if (ret == NULL) @@ -827,7 +841,16 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show *ret = fopencookie(stream, stream->mode, stream_cookie_functions); if (*ret != NULL) { + off_t pos; + stream->fclose_stdiocast = PHP_STREAM_FCLOSE_FOPENCOOKIE; + + /* If the stream position is not at the start, we need to force + * the stdio layer to believe it's real location. */ + pos = php_stream_tell(stream); + if (pos > 0) + fseek(*ret, pos, SEEK_SET); + goto exit_success; } @@ -840,13 +863,10 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show return FAILURE; #endif - goto exit_fail; } if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) goto exit_success; - -exit_fail: if (show_err) { /* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */ static const char *cast_names[3] = { @@ -866,7 +886,7 @@ exit_fail: exit_success: if (castas == PHP_STREAM_AS_STDIO && ret) stream->stdiocast = *ret; - + if (flags & PHP_STREAM_CAST_RELEASE) { /* Something other than php_stream_close will be closing * the underlying handle, so we should free the stream handle/data @@ -983,6 +1003,7 @@ PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options, stream = php_stream_fopen_rel(path, mode, opened_path); out: + if (stream != NULL && (options & STREAM_MUST_SEEK)) { php_stream *newstream; @@ -1014,6 +1035,27 @@ out: return stream; } +PHPAPI FILE * _php_stream_open_wrapper_as_file(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC) +{ + FILE *fp = NULL; + php_stream *stream = NULL; + + stream = php_stream_open_wrapper(path, mode, options, opened_path); + + if (stream == NULL) + return NULL; + + if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE, + (void**)&fp, REPORT_ERRORS) == FAILURE) + { + php_stream_close(stream); + if (opened_path && *opened_path) + efree(*opened_path); + return NULL; + } + return fp; +} + #define PHP_STREAM_MAX_MEM 2 * 1024 * 1024 PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC) @@ -1044,7 +1086,8 @@ PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstr } php_stream_close(origstream); - + php_stream_seek(*newstream, 0, SEEK_SET); + return PHP_STREAM_RELEASED; } -- 2.50.1