ostream-file.c revision 8f32e59200da904613506f5649ffa4d9f5989ceb
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
/* @UNSAFE: whole file */
#include "lib.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 {
struct ostream_private ostream;
int fd;
unsigned char *buffer; /* ring-buffer */
unsigned int file:1;
unsigned int corked:1;
unsigned int flush_pending:1;
unsigned int socket_cork_set: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 */
}
{
}
{
/* ...HXXXT... */
} else {
/* XXXT...HXXX */
}
}
{
return;
/* ...HXXXT... */
} else {
/* XXXT...HXXX */
} else {
}
}
}
{
if (!fstream->no_socket_cork) {
else
}
}
}
{
return 0;
if (ret < 0) {
return -1;
}
return -1;
}
return 0;
}
{
bool partial;
int i;
if (iov_size == 1) {
if (ret > 0)
} else {
}
} else {
if (o_stream_lseek(fstream) < 0)
return -1;
size = 0;
for (i = 0; i < IOV_MAX; i++)
IOV_MAX);
break;
}
}
size = 0;
for (i = 0; i < iov_size; i++)
iov_size);
}
if (ret > 0) {
/* return what we managed to get sent */
}
}
if (ret < 0) {
return 0;
return -1;
}
/* assume out of disk space */
return -1;
}
/* we failed to write everything to a file. either we ran out
of disk space or we're writing to NFS. try to write the
rest to resolve this. */
iov++;
iov_size--;
}
if (size == 0)
else {
/* write the first iov separately */
struct const_iovec new_iov;
if (ret2 > 0) {
/* write the rest */
if (iov_size > 1) {
iov_size - 1);
}
}
}
if (ret2 <= 0)
return ret2;
}
return ret;
}
/* returns how much of vector was used */
{
if (IS_STREAM_EMPTY(fstream))
return 0;
return 1;
} else {
return 1;
else {
return 2;
}
}
}
{
int iov_len;
if (iov_len > 0) {
if (ret < 0)
return -1;
}
}
{
int ret;
else if (!set) {
/* buffer flushing might close the stream */
}
}
if (fstream->socket_cork_set) {
}
}
}
{
return buffer_flush(fstream);
}
static void
{
}
}
{
/* XXXT...HXXX */
/* ...HXXXT... */
} else {
/* either fully unused or fully used */
}
}
{
const struct file_ostream *fstream =
(const struct file_ostream *)stream;
}
{
return -1;
}
if (buffer_flush(fstream) < 0)
return -1;
return 1;
}
{
/* limit the size */
/* try to use optimal buffer size with corking */
}
return;
/* move head forward to end of buffer */
}
}
{
int ret;
/* Set flush_pending = FALSE first before calling the flush callback,
and change it to TRUE only if callback returns 0. That way the
callback can call o_stream_set_flush_pending() again and we don't
forget it even if flush callback returns 1. */
else
if (ret == 0)
/* all sent */
}
/* Add the IO handler if it's not there already. Callback
might have just returned 0 without there being any data
to be sent. */
}
}
}
{
int i;
sent = 0;
}
fstream);
}
return sent;
}
const struct const_iovec *iov,
unsigned int iov_count)
{
unsigned int i;
total_size = size;
if (o_stream_file_flush(stream) < 0)
return -1;
}
if (IS_STREAM_EMPTY(fstream) &&
/* send immediately */
if (ret < 0)
return -1;
iov++;
iov_count--;
}
if (iov_count == 0)
else {
/* buffer full */
return ret;
}
iov++;
iov_count--;
}
}
/* buffer it, at least partly */
for (i = 0; i < iov_count; i++) {
break;
}
return ret;
}
static size_t
{
/* ...HXXXT... */
} else {
/* XXXT...HXXX */
}
/* wraps to beginning of the buffer */
}
return size;
}
static int
{
/* update buffer if the write overlaps it */
/* updating from the beginning */
skip = 0;
} else {
}
if (left > 0) {
/* didn't write all of it */
if (skip > 0) {
/* we also have to write a prefix. don't
bother with two syscalls, just write all
of it in one pwrite(). */
} else {
/* write only the suffix */
}
} else if (skip == 0) {
/* everything done */
return 0;
} else {
/* still have to write prefix */
}
}
/* we couldn't write everything to the buffer. flush the buffer
and pwrite() the rest. */
if (o_stream_file_flush(stream) < 0)
return -1;
return -1;
}
return 0;
}
{
return -1;
}
/* flush out any data in buffer */
return ret;
if (o_stream_lseek(foutstream) < 0)
return -1;
do {
if (ret <= 0) {
ret = 0;
break;
}
/* close only if error wasn't because
sendfile() isn't supported */
}
break;
}
if (ret == 0) {
/* we should be at EOF, verify it by reading instream */
(void)i_stream_read(instream);
}
}
{
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 or the file gets corrupted */
}
break;
}
/* buffer too large probably, try with smaller */
out_offset += read_size;
buffer_size -= read_size;
}
if (ret < 0) {
/* error */
return -1;
}
}
}
{
if (same_stream) {
/* copying data within same fd. we'll have to be careful with
seeks and overlapping writes. */
return -1;
}
if (ret == 0) {
/* copying data over itself. we don't really
need to do that, just fake it. */
}
/* overlapping */
}
}
}
{
bool same_stream;
int in_fd;
return ret;
/* sendfile() not supported (with this fd), fallback to
regular sending. */
}
}
static struct file_ostream *
{
struct file_ostream *fstream;
return fstream;
}
{
return;
/* use the optimal block size, but with a reasonable limit */
}
}
}
struct ostream *
{
struct file_ostream *fstream;
if (offset >= 0) {
} else {
}
}
if (max_buffer_size == 0)
return ostream;
}
struct ostream *
{
struct file_ostream *fstream;
return ostream;
}