diff options
-rw-r--r-- | source3/lib/recvfile.c | 31 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 |
2 files changed, 26 insertions, 7 deletions
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c index 9d77f94a29..a009ce9dd6 100644 --- a/source3/lib/recvfile.c +++ b/source3/lib/recvfile.c @@ -39,7 +39,7 @@ * * Returns number of bytes written to 'tofd' * or thrown away if 'tofd == -1'. - * eturn != count then sets errno. + * return != count then sets errno. * Returns count if complete success. */ @@ -140,18 +140,26 @@ _syscall6( long, splice, unsigned int, flags); #endif +/* + * Try and use the Linux system call to do this. + * Remember we only return -1 if the socket read + * failed. Else we return the number of bytes + * actually written. We always read count bytes + * from the network in the case of return != -1. + */ + ssize_t sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset, size_t count) { - size_t total = 0; + size_t total_written = 0; if (count == 0) { return 0; } - while (total < count) { + while (total_written < count) { ssize_t ret = splice(fromfd, NULL, tofd, @@ -160,14 +168,25 @@ ssize_t sys_recvfile(int fromfd, 0); if (ret == -1) { if (errno != EINTR) { - return -1; + break; } continue; } - total += ret; + total_written += ret; count -= ret; } - return total; + + if (total_written < count) { + int saved_errno = errno; + if (drain_socket(fromfd, count-total_written) != + count-total_written) { + /* socket is dead. */ + return -1; + } + errno = saved_errno; + } + + return total_written; } #else diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 4c1ed56d4f..531e71fe73 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3698,7 +3698,7 @@ void reply_writeunlock(connection_struct *conn, struct smb_request *req) return; } - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { + if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) { reply_unixerror(req, ERRHRD, ERRdiskfull); END_PROFILE(SMBwriteunlock); return; |