ostream-file.c revision aa53b2ab36519f431a1398e86c31efafc9cf6243
/* Copyright (c) 2002-2003 Timo Sirainen */
/* @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
#ifndef UIO_MAXIOV
# define UIO_MAXIOV 16
#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 */
unsigned int file:1;
unsigned int corked:1;
unsigned int no_socket_cork:1;
unsigned int no_sendfile:1;
unsigned int autoclose_fd:1;
};
static void stream_send_io(void *context);
{
i_error("file_ostream.close() failed: %m");
}
}
}
{
/* flush output before really closing it */
}
{
}
{
}
{
return;
/* ...HXXXT... */
} else {
/* XXXT...HXXX */
} else {
}
}
}
{
int i;
if (iov_size == 1)
else {
sent = 0;
while (iov_size > UIO_MAXIOV) {
size = 0;
for (i = 0; i < UIO_MAXIOV; i++)
break;
iov += UIO_MAXIOV;
iov_size -= UIO_MAXIOV;
}
if (iov_size <= UIO_MAXIOV) {
iov_size);
}
if (ret > 0)
}
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;
}
}
}
{
int iov_len;
if (iov_len > 0) {
if (ret < 0)
return -1;
}
}
{
if (!fstream->no_socket_cork) {
}
else {
}
}
}
}
{
return buffer_flush(fstream);
}
{
/* XXXT...HXXX */
/* ...HXXXT... */
} else {
/* either fully unused or fully used */
}
}
{
}
{
return -1;
}
if (buffer_flush(fstream) < 0)
return -1;
if (ret < 0) {
return -1;
}
return -1;
}
return 1;
}
{
/* limit the size */
/* try to use optimal buffer size with corking */
}
return;
/* move head forward to end of buffer */
}
}
static void stream_send_io(void *context)
{
int ret;
else
/* all sent */
}
}
{
int i;
sent = 0;
}
fstream);
}
return sent;
}
{
return -1;
}
if (IS_STREAM_EMPTY(fstream) &&
/* send immediately */
if (ret < 0)
return -1;
iov++;
iov_count--;
}
if (iov_count > 0) {
/* buffer full */
return ret;
}
iov++;
iov_count--;
}
}
/* buffer it, at least partly */
for (i = 0; i < iov_count; i++) {
break;
}
return ret;
}
{
/* flush out any data in buffer */
return ret;
do {
if (ret <= 0) {
ret = 0;
break;
}
/* close only if error wasn't because
sendfile() isn't supported */
}
break;
}
}
{
int iov_len;
const unsigned char *data;
int pos;
skip_size = 0;
while (in_size > 0) {
if (size == 0) {
/* all sent */
break;
}
if (ret < 0)
return -1;
if (skip_size > 0) {
ret = 0;
} else {
skip_size = 0;
}
}
break;
iov_len = 0;
}
}
{
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;
}
return -1;
if (ret < 0) {
/* error */
return -1;
}
}
}
{
int in_fd, overlapping;
overlapping = 0;
else {
/* 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. */
}
}
return ret;
/* sendfile() not supported (with this fd), fallback to
regular sending. */
}
if (overlapping <= 0)
else
}
struct ostream *
int autoclose_fd)
{
struct file_ostream *fstream;
if (offset >= 0) {
/* use the optimal block size, but with a
reasonable limit */
}
}
}
} else {
}
}
if (max_buffer_size == 0)
return ostream;
}