ostream.c revision 3d77cc0d502dc69ffe2afe318605964dd40b7b20
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenvoid o_stream_set_name(struct ostream *stream, const char *name)
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst char *o_stream_get_name(struct ostream *stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen while (stream->real_stream->iostream.name == NULL) {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenconst char *o_stream_get_error(struct ostream *stream)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen /* we'll only return errors for streams that have stream_errno set.
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen we might be returning unintended error otherwise. */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return "<no error>";
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenstatic void o_stream_close_full(struct ostream *stream, bool close_parents)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (!stream->closed && !stream->real_stream->closing) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen /* first mark the stream as being closed so the
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen o_stream_copy_error_from_parent() won't recurse us back
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen here. but don't immediately mark the stream closed, because
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen we may still want to write something to it. */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (stream->real_stream->last_errors_not_checked &&
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen !stream->real_stream->error_handling_disabled &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->iostream.refcount == 1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_panic("output stream %s is missing error handling",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_unref(&stream->real_stream->iostream);
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenvoid o_stream_set_flush_callback(struct ostream *stream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->set_flush_callback(_stream, callback, context);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_unset_flush_callback(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->set_flush_callback(_stream, NULL, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainensize_t o_stream_get_max_buffer_size(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen errno = stream->last_failed_errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenbool o_stream_is_corked(struct ostream *stream)
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen struct ostream_private *_stream = stream->real_stream;
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen struct ostream_private *_stream = stream->real_stream;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen if (unlikely((ret = _stream->flush(_stream)) < 0)) {
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen stream->last_failed_errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_flush_pending(struct ostream *stream, bool set)
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen struct ostream_private *_stream = stream->real_stream;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainensize_t o_stream_get_buffer_used_size(const struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct ostream_private *_stream = stream->real_stream;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainensize_t o_stream_get_buffer_avail_size(const struct ostream *stream)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen size_t used = o_stream_get_buffer_used_size(stream);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return stream->real_stream->max_buffer_size <= used ? 0 :
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenint o_stream_seek(struct ostream *stream, uoff_t offset)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct ostream_private *_stream = stream->real_stream;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(_stream->seek(_stream, offset) < 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen stream->last_failed_errno = stream->stream_errno;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainenssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen struct ostream_private *_stream = stream->real_stream;
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen unsigned int i;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (i = 0, total_size = 0; i < iov_count; i++)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = _stream->sendv(_stream, iov, iov_count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->last_failed_errno = stream->stream_errno;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenssize_t o_stream_send_str(struct ostream *stream, const char *str)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return o_stream_send(stream, str, strlen(str));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsend(struct ostream *stream, const void *data, size_t size)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsend_str(struct ostream *stream, const char *str)
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return stream->last_failed_errno != 0 ? -1 : 0;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid o_stream_ignore_last_errors(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->last_errors_not_checked = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_no_error_handling(struct ostream *stream, bool set)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen stream->real_stream->error_handling_disabled = set;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenoff_t o_stream_send_istream(struct ostream *outstream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_outstream = outstream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(outstream->closed || instream->closed ||
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen ret = _outstream->send_istream(_outstream, instream);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen outstream->last_failed_errno = outstream->stream_errno;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ret = stream->real_stream->write_at(stream->real_stream,
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen stream->last_failed_errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenoff_t io_stream_copy(struct ostream *outstream, struct istream *instream)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen const unsigned char *data;
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen (void)i_stream_read_data(instream, &data, &iov.iov_len, 0);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* all sent */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return (off_t)(instream->v_offset - start_offset);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenvoid o_stream_switch_ioloop(struct ostream *stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = stream->real_stream;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic void o_stream_default_close(struct iostream_private *stream,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenstatic void o_stream_default_destroy(struct iostream_private *stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_set_max_buffer_size(struct iostream_private *stream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen o_stream_set_max_buffer_size(_stream->parent, max_size);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenstatic void o_stream_default_cork(struct ostream_private *_stream, bool set)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid o_stream_copy_error_from_parent(struct ostream_private *_stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen dest->last_failed_errno = src->last_failed_errno;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint o_stream_flush_parent_if_needed(struct ostream_private *_stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we already have quite a lot of data in parent stream.
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen unless we can flush it, don't add any more to it or we
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen could keep wasting memory by just increasing the buffer
2c20ffcb5bb1ccdfdcd0b0ff0c7296f65b990362Timo Sirainen size all the time. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int o_stream_default_flush(struct ostream_private *_stream)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if ((ret = o_stream_flush(_stream->parent)) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Siraineno_stream_default_set_flush_callback(struct ostream_private *_stream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_set_flush_callback(_stream->parent, callback, context);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Siraineno_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen o_stream_set_flush_pending(_stream->parent, set);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_get_used_size(const struct ostream_private *_stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return o_stream_get_buffer_used_size(_stream->parent);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_seek(struct ostream_private *_stream,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Siraineno_stream_default_write_at(struct ostream_private *_stream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic off_t o_stream_default_send_istream(struct ostream_private *outstream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return io_stream_copy(&outstream->ostream, instream);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void o_stream_default_switch_ioloop(struct ostream_private *_stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Siraineno_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->callback = parent->real_stream->callback;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->context = parent->real_stream->context;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->max_buffer_size = parent->real_stream->max_buffer_size;
return output;
struct ostream *
return output;