1/* 2 * $Id: ad_sendfile.c,v 1.11 2010-01-21 14:14:49 didg Exp $ 3 * 4 * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) 5 * All rights reserved. See COPYRIGHT. 6 * 7 * NOTE: the following uses the fact that sendfile() only exists on 8 * machines with SA_RESTART behaviour. this is all very machine specific. 9 * 10 * sendfile chainsaw from samba. 11 Unix SMB/Netbios implementation. 12 Version 2.2.x / 3.0.x 13 sendfile implementations. 14 Copyright (C) Jeremy Allison 2002. 15 16 This program is free software; you can redistribute it and/or modify 17 it under the terms of the GNU General Public License as published by 18 the Free Software Foundation; either version 2 of the License, or 19 (at your option) any later version. 20 This program is distributed in the hope that it will be useful, 21 but WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 GNU General Public License for more details. 24 25 You should have received a copy of the GNU General Public License 26 along with this program; if not, write to the Free Software 27 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 28 */ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif /* HAVE_CONFIG_H */ 33 34#ifdef WITH_SENDFILE 35 36#include <atalk/adouble.h> 37 38#include <stdio.h> 39 40#include <sys/socket.h> 41#include <sys/uio.h> 42 43#include <errno.h> 44 45#include <atalk/logger.h> 46#include "ad_private.h" 47 48#if defined(LINUX_BROKEN_SENDFILE_API) 49 50extern int32_t sendfile (int fdout, int fdin, int32_t *offset, u_int32_t count); 51 52ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count) 53{ 54u_int32_t small_total; 55int32_t small_offset; 56int32_t nwritten; 57 58 /* 59 * Fix for broken Linux 2.4 systems with no working sendfile64(). 60 * If the offset+count > 2 GB then pretend we don't have the 61 * system call sendfile at all. The upper layer catches this 62 * and uses a normal read. JRA. 63 */ 64 65 if ((sizeof(off_t) >= 8) && (*offset + count > (off_t)0x7FFFFFFF)) { 66 errno = ENOSYS; 67 return -1; 68 } 69 small_offset = (int32_t)*offset; 70 small_total = (u_int32_t)count; 71 nwritten = sendfile(tofd, fromfd, &small_offset, small_total); 72 if (nwritten > = 0) 73 *offset += nwritten; 74 75 return nwritten; 76} 77 78#elif defined(SENDFILE_FLAVOR_LINUX) 79#include <sys/sendfile.h> 80 81ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count) 82{ 83 return sendfile(tofd, fromfd, offset, count); 84} 85 86#elif defined(SENDFILE_FLAVOR_BSD ) 87/* FIXME untested */ 88#error sendfile semantic broken 89#include <sys/sendfile.h> 90ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count) 91{ 92size_t total=0; 93int ret; 94 95 total = count; 96 while (total) { 97 ssize_t nwritten; 98 do { 99 ret = sendfile(fromfd, tofd, offset, count, NULL, &nwritten, 0); 100 while (ret == -1 && errno == EINTR); 101 if (ret == -1) 102 return -1; 103 total -= nwritten; 104 offset += nwritten; 105 } 106 return count; 107} 108 109#else 110 111ssize_t sys_sendfile(int out_fd, int in_fd, off_t *_offset, size_t count) 112{ 113 /* No sendfile syscall. */ 114 errno = ENOSYS; 115 return -1; 116} 117#endif 118 119/* ------------------------------- */ 120int ad_readfile_init(const struct adouble *ad, 121 const int eid, off_t *off, 122 const int end) 123{ 124 int fd; 125 126 if (end) 127 *off = ad_size(ad, eid) - *off; 128 129 if (eid == ADEID_DFORK) { 130 fd = ad_data_fileno(ad); 131 } else { 132 *off += ad_getentryoff(ad, eid); 133 fd = ad_reso_fileno(ad); 134 } 135 136 return fd; 137} 138 139 140/* ------------------------ */ 141#if 0 142#ifdef HAVE_SENDFILE_WRITE 143/* read from a socket and write to an adouble file */ 144ssize_t ad_writefile(struct adouble *ad, const int eid, 145 const int sock, off_t off, const int end, 146 const size_t len) 147{ 148#ifdef __linux__ 149 ssize_t cc; 150 int fd; 151 152 fd = ad_sendfile_init(ad, eid, &off, end); 153 if ((cc = sys_sendfile(fd, sock, &off, len)) < 0) 154 return -1; 155 156 if ((eid != ADEID_DFORK) && (off > ad_getentrylen(ad, eid))) 157 ad_setentrylen(ad, eid, off); 158 159 return cc; 160#endif /* __linux__ */ 161} 162#endif /* HAVE_SENDFILE_WRITE */ 163#endif /* 0 */ 164#endif 165