2 Unix SMB/Netbios implementation.
4 recvfile implementations.
5 Copyright (C) Jeremy Allison 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * This file handles the OS dependent recvfile implementations.
22 * The API is such that it returns -1 on error, else returns the
23 * number of bytes written.
28 /* Do this on our own in TRANSFER_BUF_SIZE chunks.
29 * It's safe to make direct syscalls to lseek/write here
30 * as we're below the Samba vfs layer.
32 * If tofd is -1 we just drain the incoming socket of count
33 * bytes without writing to the outgoing fd.
34 * If a write fails we do the same (to cope with disk full)
37 * Returns -1 on short reads from fromfd (read error)
40 * Returns number of bytes written to 'tofd'
41 * or thrown away if 'tofd == -1'.
42 * return != count then sets errno.
43 * Returns count if complete success.
46 #ifndef TRANSFER_BUF_SIZE
47 #define TRANSFER_BUF_SIZE (128*1024)
50 static ssize_t
default_sys_recvfile(int fromfd
,
57 size_t bufsize
= MIN(TRANSFER_BUF_SIZE
,count
);
58 size_t total_written
= 0;
61 DEBUG(10,("default_sys_recvfile: from = %d, to = %d, "
62 "offset=%.0f, count = %lu\n",
63 fromfd
, tofd
, (double)offset
,
64 (unsigned long)count
));
70 if (tofd
!= -1 && offset
!= (SMB_OFF_T
)-1) {
71 if (sys_lseek(tofd
, offset
, SEEK_SET
) == -1) {
72 if (errno
!= ESPIPE
) {
78 buffer
= SMB_MALLOC_ARRAY(char, bufsize
);
83 while (total
< count
) {
84 size_t num_written
= 0;
86 size_t toread
= MIN(bufsize
,count
- total
);
88 /* Read from socket - ignore EINTR. */
89 read_ret
= sys_read(fromfd
, buffer
, toread
);
91 /* EOF or socket error. */
98 while (num_written
< read_ret
) {
102 write_ret
= read_ret
;
104 /* Write to file - ignore EINTR. */
105 write_ret
= sys_write(tofd
,
106 buffer
+ num_written
,
107 read_ret
- num_written
);
109 if (write_ret
<= 0) {
110 /* write error - stop writing. */
117 num_written
+= (size_t)write_ret
;
118 total_written
+= (size_t)write_ret
;
126 /* Return the correct write error. */
129 return (ssize_t
)total_written
;
132 #if defined(HAVE_LINUX_SPLICE)
135 * Try and use the Linux system call to do this.
136 * Remember we only return -1 if the socket read
137 * failed. Else we return the number of bytes
138 * actually written. We always read count bytes
139 * from the network in the case of return != -1.
143 ssize_t
sys_recvfile(int fromfd
,
148 static bool try_splice_call
= true;
149 size_t total_written
= 0;
151 DEBUG(10,("sys_recvfile: from = %d, to = %d, "
152 "offset=%.0f, count = %lu\n",
153 fromfd
, tofd
, (double)offset
,
154 (unsigned long)count
));
161 * Older Linux kernels have splice for sendfile,
162 * but it fails for recvfile. Ensure we only try
163 * this once and always fall back to the userspace
164 * implementation if recvfile splice fails. JRA.
167 if (!try_splice_call
) {
168 return default_sys_recvfile(fromfd
,
174 while (total_written
< count
) {
175 ssize_t ret
= splice(fromfd
,
182 if (errno
!= EINTR
) {
183 if (total_written
== 0 &&
184 (errno
== EBADF
|| errno
== EINVAL
)) {
185 try_splice_call
= false;
186 return default_sys_recvfile(fromfd
,
195 total_written
+= ret
;
199 if (total_written
< count
) {
200 int saved_errno
= errno
;
201 if (drain_socket(fromfd
, count
-total_written
) !=
202 count
-total_written
) {
203 /* socket is dead. */
209 return total_written
;
213 /*****************************************************************
214 No recvfile system call - use the default 128 chunk implementation.
215 *****************************************************************/
217 ssize_t
sys_recvfile(int fromfd
,
222 return default_sys_recvfile(fromfd
, tofd
, offset
, count
);
226 /*****************************************************************
227 Throw away "count" bytes from the client socket.
228 *****************************************************************/
230 ssize_t
drain_socket(int sockfd
, size_t count
)
232 return default_sys_recvfile(sockfd
, -1, (SMB_OFF_T
)-1, count
);