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.
27 #include "system/filesys.h"
29 /* Do this on our own in TRANSFER_BUF_SIZE chunks.
30 * It's safe to make direct syscalls to lseek/write here
31 * as we're below the Samba vfs layer.
33 * Returns -1 on short reads from fromfd (read error)
36 * Returns number of bytes written to 'tofd'
37 * return != count then sets errno.
38 * Returns count if complete success.
41 #ifndef TRANSFER_BUF_SIZE
42 #define TRANSFER_BUF_SIZE (128*1024)
45 static ssize_t
default_sys_recvfile(int fromfd
,
52 size_t bufsize
= MIN(TRANSFER_BUF_SIZE
,count
);
53 size_t total_written
= 0;
56 DEBUG(10,("default_sys_recvfile: from = %d, to = %d, "
57 "offset=%.0f, count = %lu\n",
58 fromfd
, tofd
, (double)offset
,
59 (unsigned long)count
));
65 if (tofd
!= -1 && offset
!= (off_t
)-1) {
66 if (lseek(tofd
, offset
, SEEK_SET
) == -1) {
67 if (errno
!= ESPIPE
) {
73 while (total
< count
) {
74 size_t num_written
= 0;
76 size_t toread
= MIN(bufsize
,count
- total
);
79 * Read from socket - ignore EINTR.
80 * Can't use sys_read() as that also
81 * ignores EAGAIN and EWOULDBLOCK.
84 read_ret
= read(fromfd
, buffer
, toread
);
85 } while (read_ret
== -1 && errno
== EINTR
);
87 #if defined(EWOULDBLOCK)
88 if (read_ret
== -1 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) {
90 if (read_ret
== -1 && (errno
== EAGAIN
)) {
93 * fromfd socket is in non-blocking mode.
94 * If we already read some and wrote
95 * it successfully, return that.
96 * Only return -1 if this is the first read
97 * attempt. Caller will handle both cases.
99 if (total_written
!= 0) {
100 return total_written
;
106 /* EOF or socket error. */
112 /* Don't write any more after a write error. */
113 while (tofd
!= -1 && (num_written
< read_ret
)) {
116 /* Write to file - ignore EINTR. */
117 write_ret
= sys_write(tofd
,
118 buffer
+ num_written
,
119 read_ret
- num_written
);
121 if (write_ret
<= 0) {
122 /* write error - stop writing. */
124 if (total_written
== 0) {
134 num_written
+= (size_t)write_ret
;
135 total_written
+= (size_t)write_ret
;
142 /* Return the correct write error. */
145 return (ssize_t
)total_written
;
148 #if defined(HAVE_LINUX_SPLICE)
151 * Try and use the Linux system call to do this.
152 * Remember we only return -1 if the socket read
153 * failed. Else we return the number of bytes
154 * actually written. We always read count bytes
155 * from the network in the case of return != -1.
159 ssize_t
sys_recvfile(int fromfd
,
164 static int pipefd
[2] = { -1, -1 };
165 static bool try_splice_call
= false;
166 size_t total_written
= 0;
167 loff_t splice_offset
= offset
;
169 DEBUG(10,("sys_recvfile: from = %d, to = %d, "
170 "offset=%.0f, count = %lu\n",
171 fromfd
, tofd
, (double)offset
,
172 (unsigned long)count
));
179 * Older Linux kernels have splice for sendfile,
180 * but it fails for recvfile. Ensure we only try
181 * this once and always fall back to the userspace
182 * implementation if recvfile splice fails. JRA.
185 if (!try_splice_call
) {
186 return default_sys_recvfile(fromfd
,
192 if ((pipefd
[0] == -1) && (pipe(pipefd
) == -1)) {
193 try_splice_call
= false;
194 return default_sys_recvfile(fromfd
, tofd
, offset
, count
);
200 nread
= splice(fromfd
, NULL
, pipefd
[1], NULL
,
201 MIN(count
, 16384), SPLICE_F_MOVE
);
203 if (errno
== EINTR
) {
206 if (total_written
== 0 &&
207 (errno
== EBADF
|| errno
== EINVAL
)) {
208 try_splice_call
= false;
209 return default_sys_recvfile(fromfd
, tofd
,
212 #if defined(EWOULDBLOCK)
213 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
215 if (errno
== EAGAIN
) {
218 * fromfd socket is in non-blocking mode.
219 * If we already read some and wrote
220 * it successfully, return that.
221 * Only return -1 if this is the first read
222 * attempt. Caller will handle both cases.
224 if (total_written
!= 0) {
225 return total_written
;
233 while (to_write
> 0) {
235 thistime
= splice(pipefd
[0], NULL
, tofd
,
236 &splice_offset
, to_write
,
238 if (thistime
== -1) {
241 to_write
-= thistime
;
244 total_written
+= nread
;
250 int saved_errno
= errno
;
251 if (drain_socket(fromfd
, count
) != count
) {
252 /* socket is dead. */
258 return total_written
;
262 /*****************************************************************
263 No recvfile system call - use the default 128 chunk implementation.
264 *****************************************************************/
266 ssize_t
sys_recvfile(int fromfd
,
271 return default_sys_recvfile(fromfd
, tofd
, offset
, count
);
275 /*****************************************************************
276 Throw away "count" bytes from the client socket.
277 Returns count or -1 on error.
278 Must only operate on a blocking socket.
279 *****************************************************************/
281 ssize_t
drain_socket(int sockfd
, size_t count
)
284 size_t bufsize
= MIN(TRANSFER_BUF_SIZE
,count
);
285 char buffer
[bufsize
];
292 old_flags
= fcntl(sockfd
, F_GETFL
, 0);
293 if (set_blocking(sockfd
, true) == -1) {
297 while (total
< count
) {
299 size_t toread
= MIN(bufsize
,count
- total
);
301 /* Read from socket - ignore EINTR. */
302 read_ret
= sys_read(sockfd
, buffer
, toread
);
304 /* EOF or socket error. */
313 if (fcntl(sockfd
, F_SETFL
, old_flags
) == -1) {