ostream-file.c revision 2fb246462dc1846a299ecc5530c2b90c53edcdb4
/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
/* @UNSAFE: whole file */
#include "lib.h"
#include "ioloop.h"
#include "write-full.h"
#include "net.h"
#include "sendfile-util.h"
#include "istream.h"
#include "istream-private.h"
#include "ostream-file-private.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 IS_STREAM_EMPTY(fstream) \
#define MAX_SSIZE_T(size) \
{
i_error("file_ostream.close(%s) failed: %m",
}
}
}
bool close_parent ATTR_UNUSED)
{
/* 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) {
"lseek() failed: %m");
return -1;
}
"lseek() returned wrong value");
return -1;
}
return 0;
}
const struct const_iovec *iov,
unsigned int iov_count)
{
unsigned int i;
if (iov_count == 1) {
if (ret > 0)
} else {
}
} else {
if (o_stream_lseek(fstream) < 0)
return -1;
sent = 0;
size = 0;
for (i = 0; i < IOV_MAX; i++)
IOV_MAX);
break;
}
}
size = 0;
for (i = 0; i < iov_count; i++)
}
if (ret > 0) {
/* return what we managed to get sent */
}
}
return ret;
}
static ssize_t
const struct const_iovec *iov,
unsigned int iov_count)
{
bool partial;
unsigned int i;
for (i = 0, total_size = 0; i < iov_count; i++)
if (ret < 0) {
/* automatically retry */
}
/* try again later */
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_count--;
}
if (size == 0)
else {
/* write the first iov separately */
struct const_iovec new_iov;
if (ret2 > 0) {
/* write the rest */
if (iov_count > 1) {
iov_count - 1);
}
}
}
if (ret2 < 0)
else
}
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;
}
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->buffer_size > 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 */
if (used > 0 &&
/* 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 */
size -= update_count;
offset += update_count;
}
} 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;
}
bool *sendfile_not_supported_r)
{
return -1;
}
/* flush out any data in buffer */
return ret;
if (o_stream_lseek(foutstream) < 0)
return -1;
do {
if (ret <= 0) {
if (ret == 0)
break;
if (foutstream->file) {
/* automatically retry */
continue;
}
} else {
ret = 0;
break;
}
}
else {
/* close only if error wasn't because
sendfile() isn't supported */
}
break;
}
if (ret == 0) {
/* we should be at EOF. if not, write more. */
if (i_stream_read(instream) > 0) {
sendfile_not_supported_r) < 0)
return -1;
}
}
}
{
const unsigned char *data;
/* figure out optimal buffer size */
}
}
while (in_offset > in_start_offset) {
else
out_offset -= read_size;
for (;;) {
/* 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;
}
}
}
{
/* copying data within same fd. we'll have to be careful with
seeks and overlapping writes. */
return -1;
}
if (ret == 0) {
/* if we couldn't find out the size, it means that instream
isn't a regular file_istream. we can be reasonably sure that
we can copy it safely the regular way. (there's really no
other possibility, other than failing completely.) */
}
if (ret == 0) {
/* copying data over itself. we don't really
need to do that, just fake it. */
}
/* overlapping */
} else {
/* non-overlapping */
}
}
{
bool same_stream;
int in_fd;
bool sendfile_not_supported;
if (ret >= 0 || !sendfile_not_supported)
return ret;
/* sendfile() not supported (with this fd), fallback to
regular sending. */
}
if (!same_stream)
}
{
}
struct ostream *
{
if (max_buffer_size == 0)
return ostream;
}
{
return;
/* use the optimal block size, but with a reasonable limit */
}
}
}
struct ostream *
{
struct file_ostream *fstream;
if (offset >= 0) {
} else {
}
}
return ostream;
}
struct ostream *
{
*fd = -1;
return output;
}
struct ostream *
{
struct file_ostream *fstream;
return ostream;
}
{
*fd = -1;
return output;
}