test-istream.c revision b3987cf9620e7aba403dfd914fe76b19290713cc
0N/A/* Copyright (c) 2007-2016 Dovecot authors, see the included COPYING file */
337N/A
0N/A#include "lib.h"
0N/A#include "istream-private.h"
0N/A#include "test-common.h"
0N/A
0N/Astruct test_istream {
0N/A struct istream_private istream;
0N/A const void *orig_buffer;
0N/A unsigned int skip_diff;
0N/A size_t max_pos;
0N/A bool allow_eof;
0N/A};
0N/A
0N/Astatic ssize_t test_read(struct istream_private *stream)
0N/A{
0N/A struct test_istream *tstream = (struct test_istream *)stream;
0N/A unsigned int new_skip_diff;
0N/A size_t cur_max;
0N/A ssize_t ret;
0N/A
0N/A i_assert(stream->skip <= stream->pos);
0N/A
0N/A if (stream->pos - stream->skip >= tstream->istream.max_buffer_size) {
0N/A i_assert(stream->skip != stream->pos);
0N/A return -2;
0N/A }
0N/A
0N/A if (tstream->max_pos < stream->pos) {
0N/A /* we seeked past the end of file. */
0N/A ret = 0;
0N/A } else {
0N/A /* copy data to a buffer in somewhat random place. this could
0N/A help catch bugs. */
0N/A new_skip_diff = rand() % 128;
0N/A stream->skip = (stream->skip - tstream->skip_diff) +
0N/A new_skip_diff;
0N/A stream->pos = (stream->pos - tstream->skip_diff) +
0N/A new_skip_diff;
0N/A tstream->max_pos = (tstream->max_pos - tstream->skip_diff) +
0N/A new_skip_diff;
0N/A tstream->skip_diff = new_skip_diff;
0N/A
0N/A cur_max = tstream->max_pos;
0N/A if (stream->max_buffer_size < (size_t)-1 - stream->skip &&
0N/A cur_max > stream->skip + stream->max_buffer_size)
0N/A cur_max = stream->skip + stream->max_buffer_size;
0N/A
0N/A /* use exactly correct buffer size so valgrind can catch
0N/A read overflows */
0N/A if (stream->buffer_size != cur_max && cur_max > 0) {
0N/A stream->w_buffer = i_realloc(stream->w_buffer,
0N/A stream->buffer_size,
0N/A cur_max);
0N/A stream->buffer = stream->w_buffer;
0N/A stream->buffer_size = cur_max;
0N/A }
0N/A ssize_t size = cur_max - new_skip_diff;
0N/A if (size > 0)
0N/A memcpy(stream->w_buffer + new_skip_diff,
0N/A tstream->orig_buffer, (size_t)size);
0N/A
0N/A ret = cur_max - stream->pos;
0N/A stream->pos = cur_max;
0N/A }
0N/A
0N/A if (ret > 0)
453N/A return ret;
0N/A else if (!tstream->allow_eof ||
0N/A stream->pos - tstream->skip_diff < (uoff_t)stream->statbuf.st_size)
453N/A return 0;
0N/A else {
0N/A stream->istream.eof = TRUE;
0N/A return -1;
0N/A }
0N/A}
0N/A
0N/Astatic void test_seek(struct istream_private *stream, uoff_t v_offset,
0N/A bool mark ATTR_UNUSED)
0N/A{
0N/A struct test_istream *tstream = (struct test_istream *)stream;
0N/A
0N/A stream->istream.v_offset = v_offset;
0N/A stream->skip = v_offset + tstream->skip_diff;
0N/A stream->pos = stream->skip;
0N/A}
0N/A
0N/Astruct istream *test_istream_create_data(const void *data, size_t size)
0N/A{
0N/A struct test_istream *tstream;
0N/A
0N/A tstream = i_new(struct test_istream, 1);
0N/A tstream->orig_buffer = data;
0N/A
0N/A tstream->istream.read = test_read;
0N/A tstream->istream.seek = test_seek;
0N/A
0N/A tstream->istream.istream.blocking = FALSE;
0N/A tstream->istream.istream.seekable = TRUE;
0N/A i_stream_create(&tstream->istream, NULL, -1);
0N/A tstream->istream.statbuf.st_size = tstream->max_pos = size;
0N/A tstream->allow_eof = TRUE;
0N/A tstream->istream.max_buffer_size = (size_t)-1;
0N/A return &tstream->istream.istream;
0N/A}
0N/A
0N/Astruct istream *test_istream_create(const char *data)
0N/A{
809N/A return test_istream_create_data(data, strlen(data));
0N/A}
0N/A
0N/Astatic struct test_istream *test_istream_find(struct istream *input)
0N/A{
0N/A struct istream *in;
809N/A
0N/A for (in = input; in != NULL; in = in->real_stream->parent) {
0N/A if (in->real_stream->read == test_read)
0N/A return (struct test_istream *)in->real_stream;
0N/A }
0N/A i_panic("%s isn't test-istream", i_stream_get_name(input));
0N/A}
0N/A
0N/Avoid test_istream_set_allow_eof(struct istream *input, bool allow)
0N/A{
0N/A struct test_istream *tstream = test_istream_find(input);
0N/A
0N/A tstream->allow_eof = allow;
0N/A}
0N/A
0N/Avoid test_istream_set_max_buffer_size(struct istream *input, size_t size)
0N/A{
0N/A struct test_istream *tstream = test_istream_find(input);
0N/A
0N/A tstream->istream.max_buffer_size = size;
0N/A}
0N/A
0N/Avoid test_istream_set_size(struct istream *input, uoff_t size)
0N/A{
0N/A struct test_istream *tstream = test_istream_find(input);
0N/A
0N/A if (size > (uoff_t)tstream->istream.statbuf.st_size)
0N/A size = (uoff_t)tstream->istream.statbuf.st_size;
0N/A tstream->max_pos = size + tstream->skip_diff;
0N/A}
0N/A