}
/* }}} */
+/* }}} */
/* {{{ ------- TEMP stream implementation -------*/
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;
}
/* }}} */
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);
}
/* }}} */
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;
}
/* }}} */
#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) \
# 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;
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);
}
readchunk = maxlen - haveread;
didread = php_stream_read(src, buf, readchunk);
+
if (didread) {
/* extra paranoid */
size_t didwrite, towrite;
while(towrite) {
didwrite = php_stream_write(dest, writeptr, towrite);
-
if (didwrite == 0)
return 0; /* error */
writeptr += didwrite;
}
} else {
- if ( !maxlen) {
+ if (maxlen == 0) {
return haveread;
} else {
return 0; /* error */
break;
}
}
-
return haveread;
}
/* }}} */
-
-
/* {{{ ------- STDIO stream implementation -------*/
typedef struct {
#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);
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)
*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;
}
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] = {
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
stream = php_stream_fopen_rel(path, mode, opened_path);
out:
+
if (stream != NULL && (options & STREAM_MUST_SEEK)) {
php_stream *newstream;
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)
}
php_stream_close(origstream);
-
+ php_stream_seek(*newstream, 0, SEEK_SET);
+
return PHP_STREAM_RELEASED;
}