sesssetup.c: Add debug message.
[Samba.git] / source / lib / recvfile.c
blob6e2093335033576e08122ec82ffd7931793bc18c
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.2.x
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.
26 #include "includes.h"
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)
35 * errors.
37 * Returns -1 on short reads from fromfd (read error)
38 * and sets errno.
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)
48 #endif
50 static ssize_t default_sys_recvfile(int fromfd,
51 int tofd,
52 SMB_OFF_T offset,
53 size_t count)
55 int saved_errno = 0;
56 size_t total = 0;
57 size_t bufsize = MIN(TRANSFER_BUF_SIZE,count);
58 size_t total_written = 0;
59 char *buffer = NULL;
61 if (count == 0) {
62 return 0;
65 if (tofd != -1 && offset != (SMB_OFF_T)-1) {
66 if (sys_lseek(tofd, offset, SEEK_SET) == -1) {
67 if (errno != ESPIPE) {
68 return -1;
73 buffer = SMB_MALLOC_ARRAY(char, bufsize);
74 if (buffer == NULL) {
75 return -1;
78 while (total < count) {
79 size_t num_written = 0;
80 ssize_t read_ret;
81 size_t toread = MIN(bufsize,count - total);
83 /* Read from socket - ignore EINTR. */
84 read_ret = sys_read(fromfd, buffer, toread);
85 if (read_ret <= 0) {
86 /* EOF or socket error. */
87 free(buffer);
88 return -1;
91 num_written = 0;
93 while (num_written < read_ret) {
94 ssize_t write_ret;
96 if (tofd == -1) {
97 write_ret = read_ret;
98 } else {
99 /* Write to file - ignore EINTR. */
100 write_ret = sys_write(tofd,
101 buffer + num_written,
102 read_ret - num_written);
104 if (write_ret <= 0) {
105 /* write error - stop writing. */
106 tofd = -1;
107 saved_errno = errno;
108 continue;
112 num_written += (size_t)write_ret;
113 total_written += (size_t)write_ret;
116 total += read_ret;
119 free(buffer);
120 if (saved_errno) {
121 /* Return the correct write error. */
122 errno = saved_errno;
124 return (ssize_t)total_written;
127 #if defined(HAVE_LINUX_SPLICE)
130 * Try and use the Linux system call to do this.
131 * Remember we only return -1 if the socket read
132 * failed. Else we return the number of bytes
133 * actually written. We always read count bytes
134 * from the network in the case of return != -1.
138 ssize_t sys_recvfile(int fromfd,
139 int tofd,
140 SMB_OFF_T offset,
141 size_t count)
143 static bool try_splice_call = true;
144 size_t total_written = 0;
146 if (count == 0) {
147 return 0;
151 * Older Linux kernels have splice for sendfile,
152 * but it fails for recvfile. Ensure we only try
153 * this once and always fall back to the userspace
154 * implementation if recvfile splice fails. JRA.
157 if (!try_splice_call) {
158 return default_sys_recvfile(fromfd,
159 tofd,
160 offset,
161 count);
164 while (total_written < count) {
165 ssize_t ret = splice(fromfd,
166 NULL,
167 tofd,
168 &offset,
169 count,
171 if (ret == -1) {
172 if (errno != EINTR) {
173 if (total_written == 0 &&
174 (errno == EBADF || errno == EINVAL)) {
175 try_splice_call = false;
176 return default_sys_recvfile(fromfd,
177 tofd,
178 offset,
179 count);
181 break;
183 continue;
185 total_written += ret;
186 count -= ret;
189 if (total_written < count) {
190 int saved_errno = errno;
191 if (drain_socket(fromfd, count-total_written) !=
192 count-total_written) {
193 /* socket is dead. */
194 return -1;
196 errno = saved_errno;
199 return total_written;
201 #else
203 /*****************************************************************
204 No recvfile system call - use the default 128 chunk implementation.
205 *****************************************************************/
207 ssize_t sys_recvfile(int fromfd,
208 int tofd,
209 SMB_OFF_T offset,
210 size_t count)
212 return default_sys_recvfile(fromfd, tofd, offset, count);
214 #endif
216 /*****************************************************************
217 Throw away "count" bytes from the client socket.
218 *****************************************************************/
220 ssize_t drain_socket(int sockfd, size_t count)
222 return default_sys_recvfile(sockfd, -1, (SMB_OFF_T)-1, count);