diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | main/streams/php_stream_mmap.h | 2 | ||||
-rw-r--r-- | main/streams/plain_wrapper.c | 5 | ||||
-rw-r--r-- | main/streams/streams.c | 53 |
4 files changed, 47 insertions, 17 deletions
@@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 2020, PHP 7.4.12 +- Core: + . Fixed bug #80061 (Copying large files may have suboptimal performance). + (cmb) + - MySQLnd: . Fixed bug #80115 (mysqlnd.debug doesn't recognize absolute paths with slashes). (cmb) diff --git a/main/streams/php_stream_mmap.h b/main/streams/php_stream_mmap.h index 132f3214c1..40288cc27f 100644 --- a/main/streams/php_stream_mmap.h +++ b/main/streams/php_stream_mmap.h @@ -58,6 +58,8 @@ typedef struct { #define PHP_STREAM_MMAP_ALL 0 +#define PHP_STREAM_MMAP_MAX (512 * 1024 * 1024) + #define php_stream_mmap_supported(stream) (_php_stream_set_option((stream), PHP_STREAM_OPTION_MMAP_API, PHP_STREAM_MMAP_SUPPORTED, NULL) == 0 ? 1 : 0) /* Returns 1 if the stream in its current state can be memory mapped, diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 50ca925dea..298950cf9e 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -826,6 +826,11 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void delta = (DWORD)range->offset - loffs; } + /* MapViewOfFile()ing zero bytes would map to the end of the file; match *nix behavior instead */ + if (range->length + delta == 0) { + return PHP_STREAM_OPTION_RETURN_ERR; + } + data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, 0, loffs, range->length + delta); if (data->last_mapped_addr) { diff --git a/main/streams/streams.c b/main/streams/streams.c index f1f8bf7eab..cf411a1dd3 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1573,29 +1573,48 @@ PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size if (php_stream_mmap_possible(src)) { char *p; - size_t mapped; - p = php_stream_mmap_range(src, php_stream_tell(src), maxlen, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped); + do { + size_t chunk_size = (maxlen == 0 || maxlen > PHP_STREAM_MMAP_MAX) ? PHP_STREAM_MMAP_MAX : maxlen; + size_t mapped; - if (p) { - ssize_t didwrite = php_stream_write(dest, p, mapped); - if (didwrite < 0) { - *len = 0; - return FAILURE; - } + p = php_stream_mmap_range(src, php_stream_tell(src), chunk_size, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped); + + if (p) { + ssize_t didwrite; + + if (php_stream_seek(src, mapped, SEEK_CUR) != 0) { + php_stream_mmap_unmap(src); + break; + } + + didwrite = php_stream_write(dest, p, mapped); + if (didwrite < 0) { + *len = haveread; + return FAILURE; + } - php_stream_mmap_unmap_ex(src, mapped); + php_stream_mmap_unmap(src); - *len = didwrite; + *len = haveread += didwrite; - /* we've got at least 1 byte to read - * less than 1 is an error - * AND read bytes match written */ - if (mapped > 0 && mapped == didwrite) { - return SUCCESS; + /* we've got at least 1 byte to read + * less than 1 is an error + * AND read bytes match written */ + if (mapped == 0 || mapped != didwrite) { + return FAILURE; + } + if (mapped < chunk_size) { + return SUCCESS; + } + if (maxlen != 0) { + maxlen -= mapped; + if (maxlen == 0) { + return SUCCESS; + } + } } - return FAILURE; - } + } while (p); } while(1) { |