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