ostream-file.c revision 6449bd276af37b3e0b81a9c47ecd01f39a2cba53
/* Copyright (c) 2002-2003 Timo Sirainen */
/* @UNSAFE: whole file */
#include "lib.h"
#include "alarm-hup.h"
#include "ioloop.h"
#include "write-full.h"
#include "network.h"
#include "sendfile-util.h"
#include "istream.h"
#include "istream-internal.h"
#include "ostream-internal.h"
#include <unistd.h>
#ifdef HAVE_SYS_UIO_H
#endif
/* try to keep the buffer size within 4k..128k. ReiserFS may actually return
128k as optimal size. */
#define DEFAULT_OPTIMAL_BLOCK_SIZE 4096
#define IS_STREAM_EMPTY(fstream) \
#define MAX_SSIZE_T(size) \
struct file_ostream {
int fd;
unsigned char *buffer; /* ring-buffer */
int timeout_msecs;
void (*timeout_cb)(void *);
void *timeout_context;
unsigned int file:1;
unsigned int corked:1;
unsigned int no_socket_cork:1;
unsigned int no_sendfile:1;
unsigned int autoclose_fd:1;
};
{
i_error("file_ostream.close() failed: %m");
}
}
}
{
/* flush output before really closing it */
}
{
}
{
}
void (*timeout_cb)(void *), void *context)
{
if (timeout_msecs != 0)
}
{
if (!fstream->no_socket_cork) {
}
}
}
{
while (size > 0) {
} else {
size = 0;
}
}
}
{
if (IS_STREAM_EMPTY(fstream))
return;
/* ...HXXXT... */
} else {
/* XXXT...HXXX */
else {
/* whole buffer is sent */
}
} else {
}
}
}
/* NOTE: modifies iov */
static ssize_t
{
iov++;
iov_size--;
}
if (iov_size == 1)
else
if (ret < 0) {
return 0;
return -1;
}
return ret;
}
/* returns how much of vector was used */
{
if (IS_STREAM_EMPTY(fstream))
return 0;
return 1;
} else {
return 1;
else {
return 2;
}
}
}
{
if (size > 0) {
iov_len++;
}
if (first)
/* timeouted */
return -1;
}
return -1;
}
return 1;
}
{
int iov_len;
if (!IS_STREAM_EMPTY(fstream)) {
return -1;
if (!IS_STREAM_EMPTY(fstream)) {
return -1;
}
}
return 1;
}
{
int ret;
/* remove cork */
if (!fstream->no_socket_cork) {
i_error("net_set_cork() failed: %m");
}
}
return ret;
}
{
/* XXXT...HXXX */
/* ...HXXXT... */
} else {
/* either fully unused or fully used */
}
}
{
return 1;
if (fstream->max_buffer_size == 0)
return 1;
}
{
return -1;
}
if (buffer_flush(fstream) < 0)
return -1;
if (ret < 0) {
return -1;
}
return -1;
}
return 1;
}
{
if (fstream->max_buffer_size != 0) {
/* limit the size */
/* use the largest possible buffer with corking */
}
}
return;
else {
}
}
}
static void stream_send_io(void *context)
{
int iov_len;
/* error / all sent */
}
}
}
{
int i;
sent = 0;
}
fstream);
}
return sent;
}
{
/* never try sending immediately if fd is blocking,
so we don't need to deal with timeout issues here */
if (ret > 0)
return ret;
}
/* send it blocking */
return -1;
} else {
/* buffer it, at least partly */
}
return ret;
}
{
int first;
/* set timeout time before hflushing existing buffer which may block */
/* flush out any data in buffer */
if (buffer_flush(foutstream) < 0)
return -1;
do {
if (first)
/* timeouted */
}
ret = -1;
break;
}
if (ret < 0) {
/* close only if error wasn't because
sendfile() isn't supported */
}
break;
}
ret = 0;
if (!STREAM_IS_BLOCKING(foutstream)) {
/* don't block */
break;
}
}
}
{
int iov_len;
const unsigned char *data;
int pos;
skip_size = 0;
for (;;) {
if (overlapping)
if (size == 0) {
/* all sent */
break;
}
if (overlapping) {
return -1;
}
if (ret < 0) {
/* error */
return -1;
}
/* don't block */
break;
}
if (skip_size > 0) {
ret = 0;
} else {
skip_size = 0;
}
}
/* timeouted */
}
return -1;
}
iov_len--;
/* if we already sent the iov[0] and iov[1], we
can just remove them from future calls */
iov_len--;
}
}
}
{
const unsigned char *data;
/* figure out optimal buffer size */
}
}
while (in_offset > in_start_offset) {
else
out_offset -= read_size;
for (;;) {
read_size-1);
/* we'll have to write it through
buffer of the file gets corrupted */
}
break;
}
/* buffer too large probably,
try with smaller */
out_offset += read_size;
buffer_size -= read_size;
}
}
return -1;
if (ret < 0) {
/* error */
return -1;
}
/* timeouted */
}
return -1;
}
}
}
{
int overlapping;
return 0;
overlapping = 0;
else {
/* copying data within same fd. we'll have to be careful with
seeks and overlapping writes. */
if (ret == 0) {
/* copying data over itself. we don't really
need to do that, just fake it. */
}
return -1;
}
return ret;
/* sendfile() not supported (with this fd), fallback to
regular sending. */
}
if (overlapping <= 0)
else {
return ret;
}
}
{
return -1;
}
else {
/* easier this way so we know exactly how much data we're
moving */
return ret;
}
}
struct ostream *
int autoclose_fd)
{
struct file_ostream *fstream;
if (offset >= 0) {
/* use the optimal block size, but with a
reasonable limit */
}
}
}
#ifndef HAVE_LINUX_SENDFILE
/* only Linux supports sendfile() with non-sockets. Other
systems fail more or less gracefully if it's tried, so
don't bother to even try with them. */
#endif
} else {
}
}
return ostream;
}