1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "buffer.h"
5 #include "ostream-private.h"
6
7 struct buffer_ostream {
8 struct ostream_private ostream;
9 buffer_t *buf;
10 bool seeked;
11 };
12
o_stream_buffer_seek(struct ostream_private * stream,uoff_t offset)13 static int o_stream_buffer_seek(struct ostream_private *stream, uoff_t offset)
14 {
15 struct buffer_ostream *bstream =
16 container_of(stream, struct buffer_ostream, ostream);
17
18 bstream->seeked = TRUE;
19 stream->ostream.offset = offset;
20 return 1;
21 }
22
23 static int
o_stream_buffer_write_at(struct ostream_private * stream,const void * data,size_t size,uoff_t offset)24 o_stream_buffer_write_at(struct ostream_private *stream,
25 const void *data, size_t size, uoff_t offset)
26 {
27 struct buffer_ostream *bstream =
28 container_of(stream, struct buffer_ostream, ostream);
29
30 buffer_write(bstream->buf, offset, data, size);
31 return 0;
32 }
33
34 static ssize_t
o_stream_buffer_sendv(struct ostream_private * stream,const struct const_iovec * iov,unsigned int iov_count)35 o_stream_buffer_sendv(struct ostream_private *stream,
36 const struct const_iovec *iov, unsigned int iov_count)
37 {
38 struct buffer_ostream *bstream =
39 container_of(stream, struct buffer_ostream, ostream);
40 size_t left, n, offset;
41 ssize_t ret = 0;
42 unsigned int i;
43
44 offset = bstream->seeked ? stream->ostream.offset : bstream->buf->used;
45
46 for (i = 0; i < iov_count; i++) {
47 left = bstream->ostream.max_buffer_size -
48 stream->ostream.offset;
49 n = I_MIN(left, iov[i].iov_len);
50 buffer_write(bstream->buf, offset, iov[i].iov_base, n);
51 stream->ostream.offset += n; offset += n;
52 ret += n;
53 if (n != iov[i].iov_len)
54 break;
55 }
56 return ret;
57 }
58
59 static size_t
o_stream_buffer_get_buffer_used_size(const struct ostream_private * stream)60 o_stream_buffer_get_buffer_used_size(const struct ostream_private *stream)
61 {
62 const struct buffer_ostream *bstream =
63 container_of(stream, const struct buffer_ostream, ostream);
64
65 return bstream->buf->used;
66 }
67
o_stream_create_buffer(buffer_t * buf)68 struct ostream *o_stream_create_buffer(buffer_t *buf)
69 {
70 struct buffer_ostream *bstream;
71 struct ostream *output;
72
73 bstream = i_new(struct buffer_ostream, 1);
74 /* we don't set buffer as blocking, because if max_buffer_size is
75 changed it can get truncated. this is used in various places in
76 unit tests. */
77 bstream->ostream.max_buffer_size = SIZE_MAX;
78 bstream->ostream.seek = o_stream_buffer_seek;
79 bstream->ostream.sendv = o_stream_buffer_sendv;
80 bstream->ostream.write_at = o_stream_buffer_write_at;
81 bstream->ostream.get_buffer_used_size =
82 o_stream_buffer_get_buffer_used_size;
83
84 bstream->buf = buf;
85 output = o_stream_create(&bstream->ostream, NULL, -1);
86 o_stream_set_name(output, "(buffer)");
87 return output;
88 }
89