]> granicus.if.org Git - php/commitdiff
Improve behaviour of the stream casting operation.
authorWez Furlong <wez@php.net>
Tue, 19 Mar 2002 23:29:37 +0000 (23:29 +0000)
committerWez Furlong <wez@php.net>
Tue, 19 Mar 2002 23:29:37 +0000 (23:29 +0000)
Improve interaction with fopencookie.

main/main.c
main/memory_streams.c
main/php_streams.h
main/streams.c

index e6b8c8f0fd5ed18eb2a58c4a159d4738aff939a7..1601b2b4932564cc4805b9d27f23060c6ff425e2 100644 (file)
@@ -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;
 }
 /* }}} */
index 579bd26cada9d9ae7a4a95175c3a013320719df5..702e96f396b05d7305ad2a594323da092bbae04d 100644 (file)
@@ -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;
 }
 /* }}} */
index a590c9c94ffb6b142974da05eb088cefbad03f63..98a62286f8e62dc59851803be076c527ff477fac 100755 (executable)
@@ -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;
index 9665d8e240d90860e8f028772a2a7ee9a3b74978..687535e4b9eaa1e9fafae91003bbd7a5002f29f9 100755 (executable)
@@ -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;
 }