aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/unix/unix_efile.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers/unix/unix_efile.c')
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 4b3934657c..5b001b3819 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <sys/uio.h>
#endif
+#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
+#include <sys/sendfile.h>
+#endif
#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
#define DARWIN 1
@@ -1464,3 +1467,44 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
return check_error(0, errInfo);
#endif
}
+
+#ifdef HAVE_SENDFILE
+int
+efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, size_t *count)
+{
+#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
+ ssize_t retval = sendfile(out_fd, in_fd, offset, *count);
+ if (retval >= 0) {
+ if (retval != *count) {
+ *count = retval;
+ retval = -1;
+ errno = EAGAIN;
+ } else {
+ *count = retval;
+ }
+ } else if (retval == -1 && (errno == EINTR || errno == EAGAIN)) {
+ *count = 0;
+ }
+ return check_error(retval == -1 ? -1 : 0, errInfo);
+#elif defined(DARWIN)
+ off_t len = *count;
+ int retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
+ *count = len;
+ return check_error(retval, errInfo);
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ off_t len = 0;
+ int retval = sendfile(in_fd, out_fd, *offset, *count, NULL, &len, 0);
+ *count = len;
+ return check_error(retval, errInfo);
+#endif
+}
+#else /* no sendfile() */
+int
+efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, size_t *count)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+#endif