summaryrefslogtreecommitdiffstats
path: root/src/lib/ostream-buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ostream-buffer.c')
-rw-r--r--src/lib/ostream-buffer.c88
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;
+}