istream-seekable.c revision 448ab3576e0def2135c6f4681bd412dd59425d44
/* Copyright (c) 2005-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "str.h"
#include "memarea.h"
#include "read-full.h"
#include "write-full.h"
#include "safe-mkstemp.h"
#include "istream-private.h"
#include "istream-concat.h"
#include "istream-seekable.h"
#include <unistd.h>
struct seekable_istream {
struct istream_private istream;
char *temp_path;
void *context;
unsigned int cur_idx;
int fd;
bool free_context;
};
bool close_parent ATTR_UNUSED)
{
}
{
unsigned int i;
}
{
if (sstream->free_context)
}
static void
{
unsigned int i;
}
{
const char *path;
const unsigned char *buffer;
int fd;
if (fd == -1)
return -1;
/* copy our currently read buffer to it */
i_close_fd(&fd);
return -1;
}
/* read back the data we just had in our buffer */
for (;;) {
break;
i_error("istream-seekable: Couldn't read back "
"in-memory input %s: %s",
return -1;
}
}
/* Set the max buffer size only after we've already read everything
into memory. For example with istream-data it's possible that
more data exists in buffer than max_buffer_size. */
return 0;
}
{
return -1;
}
"read(%s) failed: %s",
return -1;
}
/* go to next stream */
/* last one, EOF */
return -1;
}
/* see if stream has pending data */
if (size != 0)
return size;
}
return ret;
}
{
const unsigned char *data;
/* This could be the first read() or we could have already
seeked backwards. */
} else {
/* need to read more */
if (size == 0) {
/* read more to buffer */
return TRUE;
}
/* we should have more now. */
/* change skip to 0 temporarily so i_stream_try_alloc() won't try to
compress the buffer. */
if (!have_space)
return FALSE;
if (size > avail_size)
size = avail_size;
}
return TRUE;
}
{
void *data;
return -1;
}
return 0;
}
{
const unsigned char *data;
return ret;
/* copy everything to temp file and use it as the stream */
if (copy_to_temp_file(sstream) < 0) {
i_unreached();
return ret;
}
}
/* need to read more */
return ret;
}
/* save to our file */
if (ret <= 0) {
i_error("istream-seekable: write_full(%s) failed: %m",
}
if (i_stream_seekable_write_failed(sstream) < 0)
return -1;
i_unreached();
return ret;
}
}
if (ret <= 0) {
} else {
ret = -2;
}
return ret;
}
static int
{
/* we've already reached EOF and know the size */
return 0;
}
/* we want to know the full size of the file, so read until
we're finished */
do {
if (ret == 0) {
i_panic("i_stream_stat() used for non-blocking "
"seekable stream %s offset %"PRIuUOFF_T,
}
return -1;
/* using a file backed buffer, we can use real fstat() */
return -1;
} else {
/* buffer is completely in memory */
}
return 0;
}
{
/* seeking backwards */
} else {
/* we can't skip over data we haven't yet read and written to
}
}
static struct istream_snapshot *
struct istream_snapshot *prev_snapshot)
{
/* still in memory */
return prev_snapshot;
} else {
/* using the fd_input stream */
}
}
struct istream *
{
struct seekable_istream *sstream;
const unsigned char *data;
unsigned int count;
i_assert(max_buffer_size > 0);
/* if any of the streams isn't blocking, set ourself also nonblocking */
}
/* initialize our buffer from first stream's pending data */
if (size > 0) {
}
}
{
unsigned int count;
return FALSE;
}
return TRUE;
}
struct istream *
void *context)
{
i_assert(max_buffer_size > 0);
/* If all input streams are seekable, use concat istream instead */
if (inputs_are_seekable(input))
return i_stream_create_concat(input);
}
{
char *temp_path_prefix = context;
int fd;
if (fd == -1) {
return -1;
}
/* we just want the fd, unlink it */
/* shouldn't happen.. */
i_close_fd(&fd);
return -1;
}
return fd;
}
struct istream *
const char *temp_path_prefix)
{
struct seekable_istream *sstream;
i_assert(max_buffer_size > 0);
if (inputs_are_seekable(input))
return i_stream_create_concat(input);
return stream;
}