diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index b414b33a8724e..31b5212a720ac 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -33,24 +33,55 @@ struct php_gz_stream_data_t { static ssize_t php_gziop_read(php_stream *stream, char *buf, size_t count) { struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; - int read; + ssize_t total_read = 0; + + /* Despite the count argument of gzread() being "unsigned int", + * the return value is "int". Error returns are values < 0, otherwise the count is returned. + * To properly distinguish error values from success value, we therefore need to cap at INT_MAX. + */ + do { + unsigned int chunk_size = MIN(count, INT_MAX); + int read = gzread(self->gz_file, buf, chunk_size); + count -= chunk_size; + + if (gzeof(self->gz_file)) { + stream->eof = 1; + } - /* XXX this needs to be looped for the case count > UINT_MAX */ - read = gzread(self->gz_file, buf, count); + if (UNEXPECTED(read < 0)) { + return read; + } - if (gzeof(self->gz_file)) { - stream->eof = 1; - } + total_read += read; + buf += read; + } while (count > 0 && !stream->eof); - return read; + return total_read; } static ssize_t php_gziop_write(php_stream *stream, const char *buf, size_t count) { struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; + ssize_t total_written = 0; + + /* Despite the count argument of gzread() being "unsigned int", + * the return value is "int". Error returns are values < 0, otherwise the count is returned. + * To properly distinguish error values from success value, we therefore need to cap at INT_MAX. + */ + do { + unsigned int chunk_size = MIN(count, INT_MAX); + int written = gzwrite(self->gz_file, buf, chunk_size); + count -= chunk_size; + + if (UNEXPECTED(written < 0)) { + return written; + } + + total_written += written; + buf += written; + } while (count > 0); - /* XXX this needs to be looped for the case count > UINT_MAX */ - return gzwrite(self->gz_file, (char *) buf, count); + return total_written; } static int php_gziop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)