diff options
Diffstat (limited to 'main')
| -rw-r--r-- | main/memory_streams.c | 9 | ||||
| -rwxr-xr-x | main/php_streams.h | 4 | ||||
| -rwxr-xr-x | main/streams.c | 78 | ||||
| -rw-r--r-- | main/user_streams.c | 96 | 
4 files changed, 148 insertions, 39 deletions
diff --git a/main/memory_streams.c b/main/memory_streams.c index e48d5faa21..520225c87c 100644 --- a/main/memory_streams.c +++ b/main/memory_streams.c @@ -216,6 +216,7 @@ php_stream_ops	php_stream_memory_ops = {  PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)  {  	php_stream_memory_data *self; +	php_stream *stream;  	self = emalloc(sizeof(*self));  	assert(self != NULL); @@ -224,7 +225,10 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)  	self->fsize = 0;  	self->smax = -1;  	self->mode = mode; -	return php_stream_alloc(&php_stream_memory_ops, self, 0, "rwb"); +	 +	stream = php_stream_alloc(&php_stream_memory_ops, self, 0, "rwb"); +	stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; +	return stream;  }  /* }}} */ @@ -435,8 +439,9 @@ PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STR  	self->smax = max_memory_usage;  	self->mode = mode;  	stream = php_stream_alloc(&php_stream_temp_ops, self, 0, "rwb"); +	stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;  	self->innerstream = php_stream_memory_create(mode); -/*	php_stream_temp_write(stream, NULL, 0 TSRMLS_CC); */ +  	return stream;  }  /* }}} */ diff --git a/main/php_streams.h b/main/php_streams.h index 5cd12839f0..8044f05026 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -377,6 +377,10 @@ PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, voi  #define PHP_STREAM_BUFFER_LINE	1	/* line buffered */  #define PHP_STREAM_BUFFER_FULL	2	/* fully buffered */ +#define PHP_STREAM_OPTION_RETURN_OK			 0 /* option set OK */ +#define PHP_STREAM_OPTION_RETURN_ERR 		-1 /* problem setting option */ +#define PHP_STREAM_OPTION_RETURN_NOTIMPL	-2 /* underlying stream does not implement; streams can handle it instead */ +  /* copy up to maxlen bytes from src to dest.  If maxlen is PHP_STREAM_COPY_ALL, copy until eof(src).   * Uses mmap if the src is a plain file and at offset 0 */  #define PHP_STREAM_COPY_ALL		-1 diff --git a/main/streams.c b/main/streams.c index e81d1bd305..7225921705 100755 --- a/main/streams.c +++ b/main/streams.c @@ -357,8 +357,36 @@ static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_D  PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)  { +	size_t avail, toread, didread = 0; +	 +	/* take from the read buffer first. +	 * It is possible that a buffered stream was switched to non-buffered, so we +	 * drain the remainder of the buffer before using the "raw" read mode for +	 * the excess */ +	avail = stream->writepos - stream->readpos; +	if (avail) { +		toread = avail; +		if (toread > size) +			toread = size; + +		memcpy(buf, stream->readbuf + stream->readpos, toread); +		stream->readpos += toread; +		size -= toread; +		buf += toread; +		didread += size; +	} + +	if (size == 0) +		return didread; +	  	if (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1) { -		return stream->ops->read(stream, buf, size TSRMLS_CC); +		if (stream->filterhead) { +			didread += stream->filterhead->fops->read(stream, stream->filterhead, +					buf, size +					TSRMLS_CC); +		} else { +			didread += stream->ops->read(stream, buf, size TSRMLS_CC); +		}  	} else {  		php_stream_fill_read_buffer(stream, size TSRMLS_CC); @@ -367,9 +395,10 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS  		memcpy(buf, stream->readbuf + stream->readpos, size);  		stream->readpos += size; -		stream->position += size; -		return size; +		didread += size;  	} +	stream->position += size; +	return didread;  }  PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC) @@ -550,7 +579,7 @@ PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC)  PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)  {  	/* not moving anywhere */ -	if (offset == 0 && whence == SEEK_CUR) +	if ((offset == 0 && whence == SEEK_CUR) || (offset == stream->position && whence == SEEK_SET))  		return 0;  	/* handle the case where we are in the buffer */ @@ -576,6 +605,8 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_  	stream->readpos = stream->writepos = 0;  	if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { +		int ret; +		  		if (stream->filterhead)  			stream->filterhead->fops->flush(stream, stream->filterhead, 0 TSRMLS_CC); @@ -585,7 +616,12 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_  				whence = SEEK_SET;  				break;  		} -		return stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC); +		ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC); + +		if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) +			return ret; +		/* else the stream has decided that it can't support seeking after all; +		 * fall through to attempt emulation */  	}  	/* emulate forward moving seeks with reads */ @@ -603,16 +639,37 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_  		return 0;  	} -	php_error_docref(NULL TSRMLS_CC, E_WARNING, "streams of type %s do not support seeking", stream->ops->label); +	php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream does not support seeking");  	return -1;  }  PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)  { -	if (stream->ops->set_option) -		return stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC); -	return -1; +	int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL; +	 +	if (stream->ops->set_option) { +		ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC); +	} +	 +	if (ret == PHP_STREAM_OPTION_RETURN_NOTIMPL) { +		switch(option) { +			case PHP_STREAM_OPTION_BUFFER: +				/* try to match the buffer mode as best we can */ +				if (value == PHP_STREAM_BUFFER_NONE) { +					stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; +				} else { +					stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; +				} +				ret = PHP_STREAM_OPTION_RETURN_OK; +				break; +				 +			default: +				ret = PHP_STREAM_OPTION_RETURN_ERR; +		} +	} +	 +	return ret;  }  PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC) @@ -1097,12 +1154,15 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void  			switch(value) {  				case PHP_STREAM_BUFFER_NONE: +					stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;  					return setvbuf(data->file, NULL, _IONBF, 0);  				case PHP_STREAM_BUFFER_LINE: +					stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;  					return setvbuf(data->file, NULL, _IOLBF, size);  				case PHP_STREAM_BUFFER_FULL: +					stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;  					return setvbuf(data->file, NULL, _IOFBF, size);  				default: diff --git a/main/user_streams.c b/main/user_streams.c index 248e0a3548..cce999da58 100644 --- a/main/user_streams.c +++ b/main/user_streams.c @@ -85,29 +85,46 @@ typedef struct _php_userstream_data php_userstream_data_t;  /* class should have methods like these: -function stream_open($path, $mode, $options, &$opened_path) -   { -      return true/false; -   } -   function stream_read($count) -   { -      return false on error; -      else return string; -   } -   function stream_write($data) -   { -      return false on error; -      else return count written; -   } -   function stream_close() -   { -   } -   function stream_flush() -   { -   } -   function stream_seek($offset, $whence) -   { -   } +	function stream_open($path, $mode, $options, &$opened_path) +	{ +	  	return true/false; +	} +	 +	function stream_read($count) +	{ +	   	return false on error; +		else return string; +	} +	 +	function stream_write($data) +	{ +	   	return false on error; +		else return count written; +	} +	 +	function stream_close() +	{ +	} +	 +	function stream_flush() +	{ +		return true/false; +	} +	 +	function stream_seek($offset, $whence) +	{ +		return true/false; +	} + +	function stream_tell() +	{ +		return (int)$position; +	} + +	function stream_eof() +	{ +		return true/false; +	}   **/ @@ -267,6 +284,9 @@ static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t  	if (call_result == SUCCESS && retval != NULL) {  		convert_to_long_ex(&retval);  		didwrite = Z_LVAL_P(retval); +	} else if (call_result == FAILURE) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " - is not implemented!", +				us->wrapper->classname);  	}  	/* don't allow strange buffer overruns due to bogus return */ @@ -305,8 +325,14 @@ static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count  		if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))  			didread = 0; -		else +		else { +			if (call_result == FAILURE) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_EOF " - is not implemented! Assuming EOF", +						us->wrapper->classname); +			} +  			didread = EOF; +		}  	} else {  		zval *zcount; @@ -334,8 +360,10 @@ static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count  			}  			if (didread > 0)  				memcpy(buf, Z_STRVAL_P(retval), didread); +		} else if (call_result == FAILURE) { +			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " - is not implemented!", +					us->wrapper->classname);  		} -  		zval_ptr_dtor(&zcount);  	} @@ -430,10 +458,19 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o  	zval_ptr_dtor(&zoffs);  	zval_ptr_dtor(&zwhence); -	if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG) -		ret = Z_LVAL_P(retval); -	else +	if (call_result == FAILURE) { +		/* stream_seek is not implemented, so disable seeks for this stream */ +		stream->flags |= PHP_STREAM_FLAG_NO_SEEK; +		/* there should be no retval to clean up */ +		return -1; +	} else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) { +		ret = 0; +	} else {  		ret = -1; +	} + +	if (retval) +		zval_ptr_dtor(&retval);  	/* now determine where we are */  	ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1, 0); @@ -446,6 +483,9 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o  	if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG)  		*newoffs = Z_LVAL_P(retval); +	else +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_TELL " - is not implemented!", +				us->wrapper->classname);  	if (retval)  		zval_ptr_dtor(&retval);  | 
