|
29 | 29 | #include "ext/standard/basic_functions.h" /* for BG(CurrentStatFile) */
|
30 | 30 | #include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */
|
31 | 31 | #include <stddef.h>
|
| 32 | +#if defined(HAVE_SYS_SENDFILE_H) |
| 33 | +#include <sys/sendfile.h> |
| 34 | +#endif |
32 | 35 | #include <fcntl.h>
|
33 | 36 | #include "php_streams_int.h"
|
34 | 37 |
|
@@ -1575,7 +1578,7 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de
|
1575 | 1578 | php_stream_cast(src, PHP_STREAM_AS_FD, (void*)&src_fd, 0);
|
1576 | 1579 | php_stream_cast(dest, PHP_STREAM_AS_FD, (void*)&dest_fd, 0);
|
1577 | 1580 |
|
1578 |
| - /* clamp to INT_MAX to avoid EOVERFLOW */ |
| 1581 | + /* clamp to SIZE_MAX to avoid EOVERFLOW */ |
1579 | 1582 | const size_t cfr_max = MIN(maxlen, (size_t)SSIZE_MAX);
|
1580 | 1583 |
|
1581 | 1584 | /* copy_file_range() is a Linux-specific system call
|
@@ -1638,6 +1641,53 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de
|
1638 | 1641 | }
|
1639 | 1642 | #endif // __FreeBSD__
|
1640 | 1643 | #endif // HAVE_COPY_FILE_RANGE
|
| 1644 | +#ifdef HAVE_SENDFILEV |
| 1645 | + if (php_stream_is(src, PHP_STREAM_IS_STDIO) && |
| 1646 | + php_stream_is(dest, PHP_STREAM_IS_STDIO) && |
| 1647 | + src->writepos == src->readpos && |
| 1648 | + dest->mode[0] == 'w' && |
| 1649 | + php_stream_can_cast(src, PHP_STREAM_AS_FD) == SUCCESS && |
| 1650 | + php_stream_can_cast(dest, PHP_STREAM_AS_FD) == SUCCESS) { |
| 1651 | + int src_fd, dest_fd; |
| 1652 | + |
| 1653 | + php_stream_cast(src, PHP_STREAM_AS_FD, (void*)&src_fd, 0); |
| 1654 | + php_stream_cast(dest, PHP_STREAM_AS_FD, (void*)&dest_fd, 0); |
| 1655 | + |
| 1656 | + /* clamp to INT_MAX to avoid EOVERFLOW */ |
| 1657 | + const size_t cfr_max = MIN(maxlen, (size_t)INT_MAX); |
| 1658 | + struct sendfilevec vec = { |
| 1659 | + .sfv_fd = src_fd, |
| 1660 | + .sfv_flag = 0, |
| 1661 | + .sfv_off = 0, |
| 1662 | + .sfv_len = cfr_max, |
| 1663 | + }; |
| 1664 | + ssize_t result = -1; |
| 1665 | + size_t nbytes = 0; |
| 1666 | + /* we use the syscall only when output is in write mode */ |
| 1667 | + do { |
| 1668 | + result = sendfilev(dest_fd, &vec, 1, &nbytes); |
| 1669 | + } while (result == -1 && errno == EAGAIN); |
| 1670 | + |
| 1671 | + if (result > 0) { |
| 1672 | + haveread += nbytes; |
| 1673 | + |
| 1674 | + src->position += nbytes; |
| 1675 | + dest->position += nbytes; |
| 1676 | + |
| 1677 | + if ((maxlen != PHP_STREAM_COPY_ALL && nbytes == maxlen) || |
| 1678 | + php_stream_eof(src)) { |
| 1679 | + *len = haveread; |
| 1680 | + return SUCCESS; |
| 1681 | + } |
| 1682 | + } else if (result == 0) { |
| 1683 | + *len = haveread; |
| 1684 | + return SUCCESS; |
| 1685 | + } else if (result < 0) { |
| 1686 | + *len = haveread; |
| 1687 | + return FAILURE; |
| 1688 | + } |
| 1689 | + } |
| 1690 | +#endif // HAVE_SENDFILEV |
1641 | 1691 |
|
1642 | 1692 | if (maxlen == PHP_STREAM_COPY_ALL) {
|
1643 | 1693 | maxlen = 0;
|
|
0 commit comments