Report errors from stream read and write operations

The php_stream_read() and php_stream_write() functions now return
an ssize_t value, with negative results indicating failure. Functions
like fread() and fwrite() will return false in that case.

As a special case, EWOULDBLOCK and EAGAIN on non-blocking streams
should not be regarded as error conditions, and be reported as
successful zero-length reads/writes instead. The handling of EINTR
remains unclear and is internally inconsistent (e.g. some code-paths
will automatically retry on EINTR, while some won't).

I'm landing this now to make sure the stream wrapper ops API changes
make it into 7.4 -- however, if the user-facing changes turn out to
be problematic we have the option of clamping negative returns to
zero in php_stream_read() and php_stream_write() to restore the
old behavior in a relatively non-intrusive manner.
This commit is contained in:
Nikita Popov 2019-07-18 15:25:59 +02:00
parent c817b8020c
commit d59aac58b3
73 changed files with 648 additions and 377 deletions

View file

@ -115,8 +115,8 @@ typedef struct _php_stream_dirent {
/* operations on streams that are file-handles */
typedef struct _php_stream_ops {
/* stdio like functions - these are mandatory! */
size_t (*write)(php_stream *stream, const char *buf, size_t count);
size_t (*read)(php_stream *stream, char *buf, size_t count);
ssize_t (*write)(php_stream *stream, const char *buf, size_t count);
ssize_t (*read)(php_stream *stream, char *buf, size_t count);
int (*close)(php_stream *stream, int close_handle);
int (*flush)(php_stream *stream);
@ -305,17 +305,19 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence);
PHPAPI zend_off_t _php_stream_tell(php_stream *stream);
#define php_stream_tell(stream) _php_stream_tell((stream))
PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t count);
PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t count);
#define php_stream_read(stream, buf, count) _php_stream_read((stream), (buf), (count))
PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count);
PHPAPI zend_string *php_stream_read_to_str(php_stream *stream, size_t len);
PHPAPI ssize_t _php_stream_write(php_stream *stream, const char *buf, size_t count);
#define php_stream_write_string(stream, str) _php_stream_write(stream, str, strlen(str))
#define php_stream_write(stream, buf, count) _php_stream_write(stream, (buf), (count))
PHPAPI void _php_stream_fill_read_buffer(php_stream *stream, size_t size);
PHPAPI int _php_stream_fill_read_buffer(php_stream *stream, size_t size);
#define php_stream_fill_read_buffer(stream, size) _php_stream_fill_read_buffer((stream), (size))
PHPAPI size_t _php_stream_printf(php_stream *stream, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPAPI ssize_t _php_stream_printf(php_stream *stream, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
/* php_stream_printf macro & function require */
#define php_stream_printf _php_stream_printf
@ -462,7 +464,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
#define php_stream_copy_to_mem(src, maxlen, persistent) _php_stream_copy_to_mem((src), (maxlen), (persistent) STREAMS_CC)
/* output all data from a stream */
PHPAPI size_t _php_stream_passthru(php_stream * src STREAMS_DC);
PHPAPI ssize_t _php_stream_passthru(php_stream * src STREAMS_DC);
#define php_stream_passthru(stream) _php_stream_passthru((stream) STREAMS_CC)
END_EXTERN_C()