diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/ostream-buffer.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/lib/ostream-buffer.c b/src/lib/ostream-buffer.c new file mode 100644 index 0000000..af3dbef --- /dev/null +++ b/src/lib/ostream-buffer.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "ostream-private.h" + +struct buffer_ostream { + struct ostream_private ostream; + buffer_t *buf; + bool seeked; +}; + +static int o_stream_buffer_seek(struct ostream_private *stream, uoff_t offset) +{ + struct buffer_ostream *bstream = + container_of(stream, struct buffer_ostream, ostream); + + bstream->seeked = TRUE; + stream->ostream.offset = offset; + return 1; +} + +static int +o_stream_buffer_write_at(struct ostream_private *stream, + const void *data, size_t size, uoff_t offset) +{ + struct buffer_ostream *bstream = + container_of(stream, struct buffer_ostream, ostream); + + buffer_write(bstream->buf, offset, data, size); + return 0; +} + +static ssize_t +o_stream_buffer_sendv(struct ostream_private *stream, + const struct const_iovec *iov, unsigned int iov_count) +{ + struct buffer_ostream *bstream = + container_of(stream, struct buffer_ostream, ostream); + size_t left, n, offset; + ssize_t ret = 0; + unsigned int i; + + offset = bstream->seeked ? stream->ostream.offset : bstream->buf->used; + + for (i = 0; i < iov_count; i++) { + left = bstream->ostream.max_buffer_size - + stream->ostream.offset; + n = I_MIN(left, iov[i].iov_len); + buffer_write(bstream->buf, offset, iov[i].iov_base, n); + stream->ostream.offset += n; offset += n; + ret += n; + if (n != iov[i].iov_len) + break; + } + return ret; +} + +static size_t +o_stream_buffer_get_buffer_used_size(const struct ostream_private *stream) +{ + const struct buffer_ostream *bstream = + container_of(stream, const struct buffer_ostream, ostream); + + return bstream->buf->used; +} + +struct ostream *o_stream_create_buffer(buffer_t *buf) +{ + struct buffer_ostream *bstream; + struct ostream *output; + + bstream = i_new(struct buffer_ostream, 1); + /* we don't set buffer as blocking, because if max_buffer_size is + changed it can get truncated. this is used in various places in + unit tests. */ + bstream->ostream.max_buffer_size = SIZE_MAX; + bstream->ostream.seek = o_stream_buffer_seek; + bstream->ostream.sendv = o_stream_buffer_sendv; + bstream->ostream.write_at = o_stream_buffer_write_at; + bstream->ostream.get_buffer_used_size = + o_stream_buffer_get_buffer_used_size; + + bstream->buf = buf; + output = o_stream_create(&bstream->ostream, NULL, -1); + o_stream_set_name(output, "(buffer)"); + return output; +} |