Third part of fix for bug #8679 - recvfile code path using splice() on Linux leaves...
authorJeremy Allison <jra@samba.org>
Sat, 31 Dec 2011 04:45:10 +0000 (20:45 -0800)
committerJeremy Allison <jra@samba.org>
Sat, 31 Dec 2011 04:45:10 +0000 (20:45 -0800)
Fix default_sys_recvfile() to correctly cope with
short writes. Return the amount written. Return
-1 and set errno if no data could be written.

source3/lib/recvfile.c

index 31d9311498d2399df4318b3bdf56734c4a4b11d5..c74cdd5a67d94a0a028db86ea6df53aa12ca1cbb 100644 (file)
  * It's safe to make direct syscalls to lseek/write here
  * as we're below the Samba vfs layer.
  *
- * If tofd is -1 we just drain the incoming socket of count
- * bytes without writing to the outgoing fd.
- * If a write fails we do the same (to cope with disk full)
- * errors.
- *
  * Returns -1 on short reads from fromfd (read error)
  * and sets errno.
  *
  * Returns number of bytes written to 'tofd'
- * or thrown away if 'tofd == -1'.
  * return != count then sets errno.
  * Returns count if complete success.
  */
@@ -96,23 +90,26 @@ static ssize_t default_sys_recvfile(int fromfd,
 
                num_written = 0;
 
-               while (num_written < read_ret) {
+               /* Don't write any more after a write error. */
+               while (tofd != -1 && (num_written < read_ret)) {
                        ssize_t write_ret;
 
-                       if (tofd == -1) {
-                               write_ret = read_ret;
-                       } else {
-                               /* Write to file - ignore EINTR. */
-                               write_ret = sys_write(tofd,
-                                               buffer + num_written,
-                                               read_ret - num_written);
-
-                               if (write_ret <= 0) {
-                                       /* write error - stop writing. */
-                                       tofd = -1;
-                                       saved_errno = errno;
-                                       continue;
-                               }
+                       /* Write to file - ignore EINTR. */
+                       write_ret = sys_write(tofd,
+                                       buffer + num_written,
+                                       read_ret - num_written);
+
+                       if (write_ret <= 0) {
+                               /* write error - stop writing. */
+                               tofd = -1;
+                                if (total_written == 0) {
+                                       /* Ensure we return
+                                          -1 if the first
+                                          write failed. */
+                                        total_written = -1;
+                                }
+                               saved_errno = errno;
+                               break;
                        }
 
                        num_written += (size_t)write_ret;