summaryrefslogtreecommitdiff
path: root/source3/lib/recvfile.c
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2008-12-23 22:45:03 +0100
committerVolker Lendecke <vl@samba.org>2008-12-31 19:33:25 +0100
commite0fd61f0cbfb0a25c8e9603375c2eb98936c8345 (patch)
treed285caeb919585de2f84d1492172f7e0d93d97cc /source3/lib/recvfile.c
parent9e1cabdd43bb608c6aa707f0e42d99e204e86603 (diff)
downloadsamba-e0fd61f0cbfb0a25c8e9603375c2eb98936c8345.tar.gz
samba-e0fd61f0cbfb0a25c8e9603375c2eb98936c8345.tar.bz2
samba-e0fd61f0cbfb0a25c8e9603375c2eb98936c8345.zip
Try to fix recvfile using splice on Linux
According to the splice(2) manpage, one of the file descriptors *must* be a pipe. With this patch I could successfully run splice(2) on a debian lenny installation. Jeremy, please check!
Diffstat (limited to 'source3/lib/recvfile.c')
-rw-r--r--source3/lib/recvfile.c57
1 files changed, 36 insertions, 21 deletions
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index 513742ce8f..41f7213943 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -145,6 +145,7 @@ ssize_t sys_recvfile(int fromfd,
SMB_OFF_T offset,
size_t count)
{
+ static int pipefd[2] = { -1, -1 };
static bool try_splice_call = true;
size_t total_written = 0;
@@ -171,31 +172,45 @@ ssize_t sys_recvfile(int fromfd,
count);
}
- while (total_written < count) {
- ssize_t ret = splice(fromfd,
- NULL,
- tofd,
- &offset,
- count,
- 0);
- if (ret == -1) {
- if (errno != EINTR) {
- if (total_written == 0 &&
- (errno == EBADF || errno == EINVAL)) {
- try_splice_call = false;
- return default_sys_recvfile(fromfd,
- tofd,
- offset,
- count);
- }
- break;
+ if ((pipefd[0] == -1) && (pipe(pipefd) == -1)) {
+ try_splice_call = false;
+ return default_sys_recvfile(fromfd, tofd, offset, count);
+ }
+
+ while (count > 0) {
+ int nread, to_write;
+
+ nread = splice(fromfd, NULL, pipefd[1], NULL, count, 0);
+ if (nread == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (total_written == 0 &&
+ (errno == EBADF || errno == EINVAL)) {
+ try_splice_call = false;
+ return default_sys_recvfile(fromfd, tofd,
+ offset, count);
}
- continue;
+ break;
}
- total_written += ret;
- count -= ret;
+
+ to_write = nread;
+ while (to_write > 0) {
+ int thistime;
+ thistime = splice(pipefd[0], NULL, tofd, &offset,
+ to_write, 0);
+ if (thistime == -1) {
+ goto done;
+ }
+ offset += thistime;
+ to_write -= thistime;
+ }
+
+ total_written += nread;
+ count -= nread;
}
+ done:
if (total_written < count) {
int saved_errno = errno;
if (drain_socket(fromfd, count-total_written) !=