/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "istream-private.h"
#include "istream-concat.h"
struct concat_istream {
unsigned int input_count;
};
bool close_parent)
{
unsigned int i;
/* get the parent streams to the wanted offset */
(void)i_stream_concat_skip(cstream);
}
if (close_parent) {
for (i = 0; i < cstream->input_count; i++)
}
}
{
unsigned int i;
for (i = 0; i < cstream->input_count; i++)
}
static void
{
unsigned int i;
for (i = 0; i < cstream->input_count; i++)
}
{
const unsigned char *data;
if (cstream->prev_stream_skip != 0) {
cstream->prev_stream_skip = 0;
}
/* all the pending data is already in w_buffer */
return;
}
/* we already verified that the data size is less than the
maximum buffer size */
if (data_size > 0) {
i_unreached();
}
}
{
if (cstream->prev_stream_left == 0) {
/* no need to worry about buffers, skip everything */
/* we're still skipping inside buffer */
bytes_skipped = 0;
} else {
/* done with the buffer */
cstream->prev_stream_skip = 0;
cstream->prev_stream_left = 0;
}
}
{
const unsigned char *data;
bool last_stream;
if (data_size > cur_data_pos)
ret = 0;
else {
/* need to read more - NOTE: Can't use i_stream_read_memarea()
here, because our stream->buffer may point to the parent
istream. */
return ret;
"read(%s) failed: %s",
return -1;
}
/* we either read something or we're at EOF */
return -2;
return i_stream_concat_read(stream);
}
}
if (data_size == cur_data_pos) {
/* nothing new read - preserve the buffer as it was */
return ret;
}
if (cstream->prev_stream_left == 0) {
/* we can point directly to the current stream's buffers */
} else {
/* we still have some of the previous stream left. merge the
new data with it. */
return -2;
}
/* we'll copy all the new input to w_buffer. if we skip over
prev_stream_left bytes, the next read will switch to
pointing to cur_input's data directly. */
if (new_bytes_count > size)
}
return ret;
}
static int
unsigned int *idx_r)
{
unsigned int i;
for (i = 0; i < cstream->input_count; i++) {
if (*v_offset == 0) {
/* seek to beginning of this stream */
break;
}
if (i == cstream->unknown_size_idx) {
/* we'll need to figure out this stream's size */
"stat(%s) failed: %s",
i_error("istream-concat: stat(%s) failed: %s",
return -1;
}
/* @UNSAFE */
}
break;
}
*idx_r = i;
return 0;
}
{
cstream->prev_stream_left = 0;
cstream->prev_stream_skip = 0;
/* failed */
return;
}
else {
/* we allow seeking to EOF, but not past it. */
if (v_offset != 0) {
return;
}
/* Position ourselves at the EOF of the last actual stream. */
}
}
static int
{
unsigned int i, cur_idx;
/* make sure we have all sizes */
return -1;
for (i = 0; i < cstream->unknown_size_idx; i++)
return 0;
}
{
unsigned int count;
/* if any of the streams isn't blocking or seekable, set ourself also
if (cur_max > max_buffer_size)
}
}