1#include "network_backends.h" 2 3#if defined(USE_LINUX_SENDFILE) 4 5#include "network.h" 6#include "log.h" 7 8#include <sys/sendfile.h> 9 10#include <errno.h> 11#include <string.h> 12 13#ifdef HAVE_LIBSMBCLIENT_H 14#include <libsmbclient.h> 15#define BUFF_SIZE (1460*10) 16#endif 17 18#define DBE 0 19 20int network_write_file_chunk_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) { 21 chunk* const c = cq->first; 22 ssize_t r; 23 off_t offset; 24 off_t toSend; 25 26 force_assert(NULL != c); 27 force_assert(FILE_CHUNK == c->type); 28 force_assert(c->offset >= 0 && c->offset <= c->file.length); 29 30 offset = c->file.start + c->offset; 31 toSend = c->file.length - c->offset; 32 33 if (toSend > *p_max_bytes) toSend = *p_max_bytes; 34 35 if (0 == toSend) { 36 chunkqueue_remove_finished_chunks(cq); 37 return 0; 38 } 39 40 if (0 != network_open_file_chunk(srv, con, cq)) return -1; 41 42 if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) { 43 switch (errno) { 44 case EAGAIN: 45 case EINTR: 46 break; 47 case EPIPE: 48 case ECONNRESET: 49 return -2; 50 default: 51 log_error_write(srv, __FILE__, __LINE__, "ssd", 52 "sendfile failed:", strerror(errno), fd); 53 return -1; 54 } 55 } 56 57 if (r >= 0) { 58 chunkqueue_mark_written(cq, r); 59 *p_max_bytes -= r; 60 } 61 62 return (r > 0 && r == toSend) ? 0 : -3; 63} 64 65int network_write_smbfile_chunk_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) { 66 67 68 chunk* const c = cq->first; 69 ssize_t r; 70 off_t offset; 71 off_t toSend; 72 stat_cache_entry *sce = NULL; 73 74#ifdef HAVE_LIBSMBCLIENT_H 75 76 force_assert(NULL != c); 77 force_assert(SMB_CHUNK == c->type); 78 force_assert(c->offset >= 0 && c->offset <= c->file.length); 79 80 char buff[BUFF_SIZE]={0}; 81 82 Cdbg(DBE, "*****************************************"); 83 84 offset = c->file.start + c->offset; 85 toSend = ( c->file.length - c->offset > BUFF_SIZE) ? BUFF_SIZE : c->file.length - c->offset; 86 87 if (toSend > *p_max_bytes) toSend = *p_max_bytes; 88 89 if (0 == toSend) { 90 chunkqueue_remove_finished_chunks(cq); 91 return 0; 92 } 93 94 if (0 != network_open_file_chunk(srv, con, cq)) return -1; 95 96 //Cdbg(DBE, "c->file.fd=[%d], c->file.length=[%zu]", c->file.fd, c->file.length); 97 98 smbc_wrapper_lseek(con, c->file.fd, offset, SEEK_SET ); 99 100 //Cdbg(DBE, "offset=%zu, toSend=%zu", offset, toSend); 101 r = smbc_wrapper_read(con, c->file.fd, buff, toSend); 102 103 Cdbg(DBE, "toSend=[%lld], errno=[%d], r=[%lld]", toSend, errno, r); 104 105 if( toSend == -1 || r < 0 ) { 106 smbc_wrapper_close(con, c->file.fd); 107 108 switch (errno) { 109 case EAGAIN: 110 case EINTR: 111 break; 112 case EPIPE: 113 case ECONNRESET: 114 return -2; 115 default: 116 log_error_write(srv, __FILE__, __LINE__, "ssd", 117 "sendfile failed:", strerror(errno), fd); 118 return -1; 119 } 120 } 121 else if (r == 0) { 122 int oerrno = errno; 123 /* We got an event to write but we wrote nothing 124 * 125 * - the file shrinked -> error 126 * - the remote side closed inbetween -> remote-close */ 127 128 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { 129 /* file is gone ? */ 130 return -1; 131 } 132 133 if (offset > sce->st.st_size) { 134 /* file shrinked, close the connection */ 135 errno = oerrno; 136 137 return -1; 138 } 139 140 errno = oerrno; 141 return -2; 142 } 143 144 r = write(fd, buff, toSend); 145 146 if (r >= 0) { 147 chunkqueue_mark_written(cq, r); 148 *p_max_bytes -= r; 149 } 150#endif 151 152 return (r > 0 && r == toSend) ? 0 : -3; 153} 154 155#endif /* USE_LINUX_SENDFILE */ 156