summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/main.c14
-rw-r--r--main/memory_streams.c46
-rwxr-xr-xmain/php_streams.h5
-rwxr-xr-xmain/streams.c81
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;
}