From 23d62043ebf4bfad900935c650e8fcb3f2e6f88c Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang-solutions.com>
Date: Fri, 25 Nov 2011 11:19:54 +0100
Subject: Change nbytes to 64 bit

---
 erts/emulator/drivers/common/efile_drv.c | 26 ++++++----------
 erts/emulator/drivers/common/erl_efile.h |  2 +-
 erts/emulator/drivers/unix/unix_efile.c  | 53 ++++++++++++++++++++------------
 3 files changed, 44 insertions(+), 37 deletions(-)

(limited to 'erts')

diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 98da63f4e3..5d785a75c4 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -421,7 +421,7 @@ struct t_data
 	struct {
 	    int out_fd;
 	    off_t offset;
-	    size_t nbytes;
+	    Uint64 nbytes;
 	    Uint64 written;
 	    short flags;
 	    struct t_sendfile_hdtl *hdtl;
@@ -1728,7 +1728,7 @@ static void invoke_sendfile(void *data)
     struct t_data *d = (struct t_data *)data;
     int fd = d->fd;
     int out_fd = d->c.sendfile.out_fd;
-    size_t nbytes = d->c.sendfile.nbytes;
+    Uint64 nbytes = d->c.sendfile.nbytes;
     int result = 0;
     d->again = 0;
 
@@ -2197,12 +2197,13 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
 	  free_preadv(data);
 	  break;
       case FILE_SENDFILE:
-	  printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok);
+	//printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok);
 	  if (d->result_ok == -1) {
 	      desc->sendfile_state = not_sending;
 	      reply_error(desc, &d->errInfo);
 	      if (sys_info.async_threads != 0) {
 		  SET_NONBLOCKING(d->c.sendfile.out_fd);
+		  free_sendfile(data);
 	      } else {
 		driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd,
 			      ERL_DRV_USE, 0);
@@ -2212,6 +2213,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
 	      reply_Sint64(desc, d->c.sendfile.written);
 	      if (sys_info.async_threads != 0) {
 		SET_NONBLOCKING(d->c.sendfile.out_fd);
+		free_sendfile(data);
 	      } else {
 		driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd,
 			      ERL_DRV_USE, 0);
@@ -3367,7 +3369,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
     case FILE_SENDFILE: {
 
         struct t_data *d;
-	Uint32 out_fd, offsetH, offsetL, nbytesH, nbytesL;
+	Uint32 out_fd, offsetH, offsetL;
+	Uint64 nbytes;
 	char flags;
 
 	/* DestFD:32, Offset:64, Bytes:64,
@@ -3382,8 +3385,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
 		|| !EV_GET_CHAR(ev, &flags, &p, &q)
 		|| !EV_GET_UINT32(ev, &offsetH, &p, &q)
 		|| !EV_GET_UINT32(ev, &offsetL, &p, &q)
-		|| !EV_GET_UINT32(ev, &nbytesH, &p, &q)
-		|| !EV_GET_UINT32(ev, &nbytesL, &p, &q)) {
+		|| !EV_GET_UINT64(ev, &nbytes, &p, &q)) {
 	    /* Buffer has wrong length to contain all the needed values */
 	    reply_posix_error(desc, EINVAL);
 	    goto done;
@@ -3410,17 +3412,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
 	d->c.sendfile.offset = ((off_t) offsetH << 32) | offsetL;
     #endif
 
-    #if SIZEOF_SIZE_T == 4
-	if (nbytesH != 0) {
-	    reply_posix_error(desc, EINVAL);
-	    goto done;
-	}
-	d->c.sendfile.nbytes = (size_t) nbytesL;
-    #else
-	d->c.sendfile.nbytes = ((size_t) nbytesH << 32) | nbytesL;
-    #endif
+	d->c.sendfile.nbytes = nbytes;
 
-	printf("sendfile(nbytes => %d, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags);
+	printf("sendfile(nbytes => %ld, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags);
 
 	/* Do HEADER TRAILER stuff by calculating pointer places, not by copying data! */
 
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index e0b8cfca03..8e79b3923a 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -163,4 +163,4 @@ int efile_may_openfile(Efile_error* errInfo, char *name);
 int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
 		  int advise);
 int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
-		      off_t *offset, size_t *nbytes);
+		      off_t *offset, Uint64 *nbytes);
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 61df572a91..911ec63588 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1469,33 +1469,46 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
 }
 
 #ifdef HAVE_SENDFILE
-#define SENDFILE_CHUNK_SIZE ((1 << 30) - 1)
 int
 efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
-	       off_t *offset, size_t *nbytes)
+	       off_t *offset, Uint64 *nbytes)
 {
+  //    printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes);
+    Uint64 written = 0;
 #if defined(__linux__) || (defined(__sun) && defined(__SVR4))
-    ssize_t retval, written = 0;
-    // printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes);
-    if (*nbytes == 0) {
-	do {
-	    *nbytes = SENDFILE_CHUNK_SIZE; // chunk size
-	    retval = sendfile(out_fd, in_fd, offset, *nbytes);
-	    if (retval > 0)
-		written += retval;
-	} while (retval == SENDFILE_CHUNK_SIZE);
-    } else {
-	retval =  sendfile(out_fd, in_fd, offset, *nbytes);
-	if (retval > 0)
-	    written = retval;
-    }
+#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_SIZE_T)) - 1)
+    ssize_t retval;
+    do {
+      // check if *nbytes is 0 or greater than the largest size_t
+      if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
+	retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE);
+      else
+	retval = sendfile(out_fd, in_fd, offset, *nbytes);
+      if (retval > 0) {
+	written += retval;
+	*nbytes -= retval;
+      }
+    } while (retval == SENDFILE_CHUNK_SIZE);
     *nbytes = written;
     return check_error(retval == -1 ? -1 : 0, errInfo);
 #elif defined(DARWIN)
-    off_t len = *nbytes;
-    int retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
-    *offset += len;
-    *nbytes = len;
+#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_OFF_T)) - 1)
+    int retval;
+    off_t len;
+    do {
+      // check if *nbytes is 0 or greater than the largest off_t
+      if(*nbytes > SENDFILE_CHUNK_SIZE)
+	len = SENDFILE_CHUNK_SIZE;
+      else
+	len = *nbytes;
+      retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
+      if (retval != -1 || errno == EAGAIN || errno == EINTR) {
+        *offset += len;
+	*nbytes -= len;
+	written += len;
+      }
+    } while (len == SENDFILE_CHUNK_SIZE);
+    *nbytes = written;
     return check_error(retval, errInfo);
 #elif defined(__FreeBSD__) || defined(__DragonFly__)
     off_t len = 0;
-- 
cgit v1.2.3