changeset 16020:6cabb95d32ec

iostreams: Added close_parent flag to close() handler and clarified close/destroy APIs. This makes it unambiguous how things work: Unless you explicitly call [io]_stream_close(), the parent streams won't be closed. This is what most (hopefully all!) of the existing code expects. I was wondering a bit if [io]_stream_destroy() should simply have been removed and replaced with [io]_stream_unref() calls, since they would have worked basically everywhere, but there might be some places where it's better to have explicitly closed the stream (and where closing the parent stream doesn't matter).
author Timo Sirainen <tss@iki.fi>
date Wed, 13 Mar 2013 22:11:39 +0200
parents 34d61f447433
children e5b5e2ce7578
files src/lib-compression/istream-bzlib.c src/lib-compression/istream-zlib.c src/lib-compression/ostream-bzlib.c src/lib-compression/ostream-zlib.c src/lib-fs/ostream-cmp.c src/lib-http/http-transfer-chunked.c src/lib-mail/istream-attachment-extractor.c src/lib-mail/istream-binary-converter.c src/lib-ssl-iostream/istream-openssl.c src/lib-ssl-iostream/ostream-openssl.c src/lib/iostream-private.h src/lib/iostream-temp.c src/lib/iostream.c src/lib/istream-concat.c src/lib/istream-file.c src/lib/istream-mmap.c src/lib/istream-rawlog.c src/lib/istream-seekable.c src/lib/istream-tee.c src/lib/istream.c src/lib/istream.h src/lib/ostream-file.c src/lib/ostream-rawlog.c src/lib/ostream.c src/lib/ostream.h
diffstat 25 files changed, 124 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-compression/istream-bzlib.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-compression/istream-bzlib.c	Wed Mar 13 22:11:39 2013 +0200
@@ -23,7 +23,8 @@
 	unsigned int zs_closed:1;
 };
 
-static void i_stream_bzlib_close(struct iostream_private *stream)
+static void i_stream_bzlib_close(struct iostream_private *stream,
+				 bool close_parent)
 {
 	struct bzlib_istream *zstream = (struct bzlib_istream *)stream;
 
@@ -31,6 +32,8 @@
 		(void)BZ2_bzDecompressEnd(&zstream->zs);
 		zstream->zs_closed = TRUE;
 	}
+	if (close_parent)
+		i_stream_close(zstream->istream.parent);
 }
 
 static void bzlib_read_error(struct bzlib_istream *zstream, const char *error)
--- a/src/lib-compression/istream-zlib.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-compression/istream-zlib.c	Wed Mar 13 22:11:39 2013 +0200
@@ -40,7 +40,8 @@
 
 static void i_stream_zlib_init(struct zlib_istream *zstream);
 
-static void i_stream_zlib_close(struct iostream_private *stream)
+static void i_stream_zlib_close(struct iostream_private *stream,
+				bool close_parent)
 {
 	struct zlib_istream *zstream = (struct zlib_istream *)stream;
 
@@ -48,6 +49,8 @@
 		(void)inflateEnd(&zstream->zs);
 		zstream->zs_closed = TRUE;
 	}
+	if (close_parent)
+		i_stream_close(zstream->istream.parent);
 }
 
 static void zlib_read_error(struct zlib_istream *zstream, const char *error)
--- a/src/lib-compression/ostream-bzlib.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-compression/ostream-bzlib.c	Wed Mar 13 22:11:39 2013 +0200
@@ -20,12 +20,15 @@
 	unsigned int flushed:1;
 };
 
-static void o_stream_bzlib_close(struct iostream_private *stream)
+static void o_stream_bzlib_close(struct iostream_private *stream,
+				 bool close_parent)
 {
 	struct bzlib_ostream *zstream = (struct bzlib_ostream *)stream;
 
 	(void)o_stream_flush(&zstream->ostream.ostream);
 	(void)BZ2_bzCompressEnd(&zstream->zs);
+	if (close_parent)
+		o_stream_close(zstream->ostream.parent);
 }
 
 static int o_stream_zlib_send_outbuf(struct bzlib_ostream *zstream)
--- a/src/lib-compression/ostream-zlib.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-compression/ostream-zlib.c	Wed Mar 13 22:11:39 2013 +0200
@@ -27,12 +27,15 @@
 	unsigned int flushed:1;
 };
 
-static void o_stream_zlib_close(struct iostream_private *stream)
+static void o_stream_zlib_close(struct iostream_private *stream,
+				bool close_parent)
 {
 	struct zlib_ostream *zstream = (struct zlib_ostream *)stream;
 
 	(void)o_stream_flush(&zstream->ostream.ostream);
 	(void)deflateEnd(&zstream->zs);
+	if (close_parent)
+		o_stream_close(zstream->ostream.parent);
 }
 
 static int o_stream_zlib_send_gz_header(struct zlib_ostream *zstream)
--- a/src/lib-fs/ostream-cmp.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-fs/ostream-cmp.c	Wed Mar 13 22:11:39 2013 +0200
@@ -12,7 +12,8 @@
 	bool equals;
 };
 
-static void o_stream_cmp_close(struct iostream_private *stream)
+static void o_stream_cmp_close(struct iostream_private *stream,
+			       bool close_parent)
 {
 	struct cmp_ostream *cstream = (struct cmp_ostream *)stream;
 
@@ -21,6 +22,8 @@
 
 	i_stream_unref(&cstream->input);
 	(void)o_stream_flush(&cstream->ostream.ostream);
+	if (close_parent)
+		o_stream_close(cstream->ostream.parent);
 }
 
 bool stream_cmp_block(struct istream *input,
--- a/src/lib-http/http-transfer-chunked.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-http/http-transfer-chunked.c	Wed Mar 13 22:11:39 2013 +0200
@@ -556,13 +556,16 @@
 }
 
 static void
-http_transfer_chunked_ostream_close(struct iostream_private *stream)
+http_transfer_chunked_ostream_close(struct iostream_private *stream,
+				    bool close_parent)
 {
 	struct http_transfer_chunked_ostream *tcstream =
 		(struct http_transfer_chunked_ostream *)stream;
 
 	(void)o_stream_send(tcstream->ostream.parent, "0\r\n\r\n", 5);
 	(void)o_stream_flush(&tcstream->ostream.ostream);
+	if (close_parent)
+		o_stream_close(tcstream->ostream.parent);
 }
 
 static ssize_t
--- a/src/lib-mail/istream-attachment-extractor.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-mail/istream-attachment-extractor.c	Wed Mar 13 22:11:39 2013 +0200
@@ -627,7 +627,8 @@
 	return ret;
 }
 
-static void i_stream_attachment_extractor_close(struct iostream_private *stream)
+static void i_stream_attachment_extractor_close(struct iostream_private *stream,
+						bool close_parent)
 {
 	struct attachment_istream *astream =
 		(struct attachment_istream *)stream;
@@ -641,6 +642,8 @@
 	hash_format_deinit_free(&astream->set.hash_format);
 	if (astream->pool != NULL)
 		pool_unref(&astream->pool);
+	if (close_parent)
+		i_stream_close(astream->istream.parent);
 }
 
 struct istream *
--- a/src/lib-mail/istream-binary-converter.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-mail/istream-binary-converter.c	Wed Mar 13 22:11:39 2013 +0200
@@ -260,7 +260,8 @@
 	return new_size - old_size;
 }
 
-static void i_stream_binary_converter_close(struct iostream_private *stream)
+static void i_stream_binary_converter_close(struct iostream_private *stream,
+					    bool close_parent)
 {
 	struct binary_converter_istream *bstream =
 		(struct binary_converter_istream *)stream;
@@ -270,6 +271,8 @@
 		(void)message_parser_deinit(&bstream->parser, &parts);
 	if (bstream->pool != NULL)
 		pool_unref(&bstream->pool);
+	if (close_parent)
+		i_stream_close(bstream->istream.parent);
 }
 
 struct istream *i_stream_create_binary_converter(struct istream *input)
--- a/src/lib-ssl-iostream/istream-openssl.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-ssl-iostream/istream-openssl.c	Wed Mar 13 22:11:39 2013 +0200
@@ -10,11 +10,13 @@
 	bool seen_eof;
 };
 
-static void i_stream_ssl_close(struct iostream_private *stream)
+static void i_stream_ssl_close(struct iostream_private *stream,
+			       bool close_parent)
 {
 	struct ssl_istream *sstream = (struct ssl_istream *)stream;
 
-	i_stream_close(sstream->ssl_io->plain_input);
+	if (close_parent)
+		i_stream_close(sstream->ssl_io->plain_input);
 }
 
 static void i_stream_ssl_destroy(struct iostream_private *stream)
--- a/src/lib-ssl-iostream/ostream-openssl.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib-ssl-iostream/ostream-openssl.c	Wed Mar 13 22:11:39 2013 +0200
@@ -11,11 +11,13 @@
 	buffer_t *buffer;
 };
 
-static void o_stream_ssl_close(struct iostream_private *stream)
+static void
+o_stream_ssl_close(struct iostream_private *stream, bool close_parent)
 {
 	struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
 
-	o_stream_close(sstream->ssl_io->plain_output);
+	if (close_parent)
+		o_stream_close(sstream->ssl_io->plain_output);
 }
 
 static void o_stream_ssl_destroy(struct iostream_private *stream)
--- a/src/lib/iostream-private.h	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/iostream-private.h	Wed Mar 13 22:11:39 2013 +0200
@@ -7,7 +7,7 @@
 	int refcount;
 	char *name;
 
-	void (*close)(struct iostream_private *stream);
+	void (*close)(struct iostream_private *streami, bool close_parent);
 	void (*destroy)(struct iostream_private *stream);
 	void (*set_max_buffer_size)(struct iostream_private *stream,
 				    size_t max_size);
@@ -19,7 +19,7 @@
 void io_stream_init(struct iostream_private *stream);
 void io_stream_ref(struct iostream_private *stream);
 void io_stream_unref(struct iostream_private *stream);
-void io_stream_close(struct iostream_private *stream);
+void io_stream_close(struct iostream_private *stream, bool close_parent);
 void io_stream_set_max_buffer_size(struct iostream_private *stream,
 				   size_t max_size);
 
--- a/src/lib/iostream-temp.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/iostream-temp.c	Wed Mar 13 22:11:39 2013 +0200
@@ -27,7 +27,9 @@
 	bool fd_tried;
 };
 
-static void o_stream_temp_close(struct iostream_private *stream)
+static void
+o_stream_temp_close(struct iostream_private *stream,
+		    bool close_parent ATTR_UNUSED)
 {
 	struct temp_ostream *tstream = (struct temp_ostream *)stream;
 
--- a/src/lib/iostream.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/iostream.c	Wed Mar 13 22:11:39 2013 +0200
@@ -4,16 +4,22 @@
 #include "iostream-private.h"
 
 static void
-io_stream_default_close_destroy(struct iostream_private *stream ATTR_UNUSED)
+io_stream_default_close(struct iostream_private *stream ATTR_UNUSED,
+			bool close_parent ATTR_UNUSED)
+{
+}
+
+static void
+io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED)
 {
 }
 
 void io_stream_init(struct iostream_private *stream)
 {
 	if (stream->close == NULL)
-		stream->close = io_stream_default_close_destroy;
+		stream->close = io_stream_default_close;
 	if (stream->destroy == NULL)
-		stream->destroy = io_stream_default_close_destroy;
+		stream->destroy = io_stream_default_destroy;
 
 	stream->refcount = 1;
 }
@@ -29,7 +35,7 @@
 	if (--stream->refcount != 0)
 		return;
 
-	stream->close(stream);
+	stream->close(stream, FALSE);
 	stream->destroy(stream);
 	if (stream->destroy_callback != NULL)
 		stream->destroy_callback(stream->destroy_context);
@@ -38,9 +44,9 @@
         i_free(stream);
 }
 
-void io_stream_close(struct iostream_private *stream)
+void io_stream_close(struct iostream_private *stream, bool close_parent)
 {
-	stream->close(stream);
+	stream->close(stream, close_parent);
 }
 
 void io_stream_set_max_buffer_size(struct iostream_private *stream,
--- a/src/lib/istream-concat.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-concat.c	Wed Mar 13 22:11:39 2013 +0200
@@ -15,13 +15,16 @@
 	size_t prev_stream_left, prev_skip;
 };
 
-static void i_stream_concat_close(struct iostream_private *stream)
+static void i_stream_concat_close(struct iostream_private *stream,
+				  bool close_parent)
 {
 	struct concat_istream *cstream = (struct concat_istream *)stream;
 	unsigned int i;
 
-	for (i = 0; cstream->input[i] != NULL; i++)
-		i_stream_close(cstream->input[i]);
+	if (close_parent) {
+		for (i = 0; cstream->input[i] != NULL; i++)
+			i_stream_close(cstream->input[i]);
+	}
 }
 
 static void i_stream_concat_destroy(struct iostream_private *stream)
--- a/src/lib/istream-file.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-file.c	Wed Mar 13 22:11:39 2013 +0200
@@ -22,7 +22,8 @@
 	unsigned int seen_eof:1;
 };
 
-static void i_stream_file_close(struct iostream_private *stream)
+static void i_stream_file_close(struct iostream_private *stream,
+				bool close_parent ATTR_UNUSED)
 {
 	struct file_istream *fstream = (struct file_istream *)stream;
 	struct istream_private *_stream = (struct istream_private *)stream;
--- a/src/lib/istream-mmap.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-mmap.c	Wed Mar 13 22:11:39 2013 +0200
@@ -22,7 +22,8 @@
 
 static size_t mmap_pagemask = 0;
 
-static void i_stream_mmap_close(struct iostream_private *stream)
+static void i_stream_mmap_close(struct iostream_private *stream,
+				bool close_parent ATTR_UNUSED)
 {
 	struct mmap_istream *mstream = (struct mmap_istream *) stream;
 
--- a/src/lib/istream-rawlog.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-rawlog.c	Wed Mar 13 22:11:39 2013 +0200
@@ -10,12 +10,14 @@
 	struct rawlog_iostream riostream;
 };
 
-static void i_stream_rawlog_close(struct iostream_private *stream)
+static void i_stream_rawlog_close(struct iostream_private *stream,
+				  bool close_parent)
 {
 	struct rawlog_istream *rstream = (struct rawlog_istream *)stream;
 
 	iostream_rawlog_close(&rstream->riostream);
-	i_stream_close(rstream->istream.parent);
+	if (close_parent)
+		i_stream_close(rstream->istream.parent);
 }
 
 static void i_stream_rawlog_destroy(struct iostream_private *stream)
--- a/src/lib/istream-seekable.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-seekable.c	Wed Mar 13 22:11:39 2013 +0200
@@ -32,7 +32,8 @@
 	bool free_context;
 };
 
-static void i_stream_seekable_close(struct iostream_private *stream)
+static void i_stream_seekable_close(struct iostream_private *stream,
+				    bool close_parent ATTR_UNUSED)
 {
 	struct seekable_istream *sstream = (struct seekable_istream *)stream;
 
--- a/src/lib/istream-tee.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream-tee.c	Wed Mar 13 22:11:39 2013 +0200
@@ -65,7 +65,8 @@
 	}
 }
 
-static void i_stream_tee_close(struct iostream_private *stream)
+static void i_stream_tee_close(struct iostream_private *stream,
+			       bool close_parent ATTR_UNUSED)
 {
 	struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
 
--- a/src/lib/istream.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream.c	Wed Mar 13 22:11:39 2013 +0200
@@ -21,9 +21,18 @@
 	return stream->real_stream->iostream.name;
 }
 
+static void i_stream_close_full(struct istream *stream, bool close_parents)
+{
+	io_stream_close(&stream->real_stream->iostream, close_parents);
+	stream->closed = TRUE;
+
+	if (stream->stream_errno == 0)
+		stream->stream_errno = EPIPE;
+}
+
 void i_stream_destroy(struct istream **stream)
 {
-	i_stream_close(*stream);
+	i_stream_close_full(*stream, FALSE);
 	i_stream_unref(stream);
 }
 
@@ -71,11 +80,7 @@
 
 void i_stream_close(struct istream *stream)
 {
-	io_stream_close(&stream->real_stream->iostream);
-	stream->closed = TRUE;
-
-	if (stream->stream_errno == 0)
-		stream->stream_errno = EPIPE;
+	i_stream_close_full(stream, TRUE);
 }
 
 void i_stream_set_init_buffer_size(struct istream *stream, size_t size)
@@ -582,6 +587,15 @@
 		i_stream_set_max_buffer_size(_stream->parent, max_size);
 }
 
+static void i_stream_default_close(struct iostream_private *stream,
+				   bool close_parent)
+{
+	struct istream_private *_stream = (struct istream_private *)stream;
+
+	if (close_parent && _stream->parent != NULL)
+		i_stream_close(_stream->parent);
+}
+
 static void i_stream_default_destroy(struct iostream_private *stream)
 {
 	struct istream_private *_stream = (struct istream_private *)stream;
@@ -673,6 +687,8 @@
 	}
 	_stream->istream.real_stream = _stream;
 
+	if (_stream->iostream.close == NULL)
+		_stream->iostream.close = i_stream_default_close;
 	if (_stream->iostream.destroy == NULL)
 		_stream->iostream.destroy = i_stream_default_destroy;
 	if (_stream->seek == NULL) {
--- a/src/lib/istream.h	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/istream.h	Wed Mar 13 22:11:39 2013 +0200
@@ -43,7 +43,7 @@
    Returns "" if stream has no name. */
 const char *i_stream_get_name(struct istream *stream);
 
-/* i_stream_close() + i_stream_unref() */
+/* Close this stream (but not its parents) and unreference it. */
 void i_stream_destroy(struct istream **stream);
 
 /* Reference counting. References start from 1, so calling i_stream_unref()
@@ -65,8 +65,8 @@
 /* Return file descriptor for stream, or -1 if none is available. */
 int i_stream_get_fd(struct istream *stream);
 
-/* Mark the stream closed. Any reads after this will return -1. The data
-   already read can still be used. */
+/* Mark the stream and all of its parent streams closed. Any reads after this
+   will return -1. The data already read can still be used. */
 void i_stream_close(struct istream *stream);
 /* Sync the stream with the underlying backend, ie. if a file has been
    modified, flush any cached data. */
--- a/src/lib/ostream-file.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/ostream-file.c	Wed Mar 13 22:11:39 2013 +0200
@@ -67,7 +67,8 @@
 	fstream->ostream.ostream.closed = TRUE;
 }
 
-static void o_stream_file_close(struct iostream_private *stream)
+static void o_stream_file_close(struct iostream_private *stream,
+				bool close_parent ATTR_UNUSED)
 {
 	struct file_ostream *fstream = (struct file_ostream *)stream;
 
--- a/src/lib/ostream-rawlog.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/ostream-rawlog.c	Wed Mar 13 22:11:39 2013 +0200
@@ -10,14 +10,16 @@
 	struct rawlog_iostream riostream;
 };
 
-static void o_stream_rawlog_close(struct iostream_private *stream)
+static void o_stream_rawlog_close(struct iostream_private *stream,
+				  bool close_parent)
 {
 	struct rawlog_ostream *rstream = (struct rawlog_ostream *)stream;
 
 	(void)o_stream_flush(rstream->ostream.parent);
 	iostream_rawlog_close(&rstream->riostream);
 
-	o_stream_close(rstream->ostream.parent);
+	if (close_parent)
+		o_stream_close(rstream->ostream.parent);
 }
 
 static ssize_t
--- a/src/lib/ostream.c	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/ostream.c	Wed Mar 13 22:11:39 2013 +0200
@@ -25,9 +25,18 @@
 	return stream->real_stream->fd;
 }
 
+static void o_stream_close_full(struct ostream *stream, bool close_parents)
+{
+	io_stream_close(&stream->real_stream->iostream, close_parents);
+	stream->closed = TRUE;
+
+	if (stream->stream_errno == 0)
+		stream->stream_errno = EPIPE;
+}
+
 void o_stream_destroy(struct ostream **stream)
 {
-	o_stream_close(*stream);
+	o_stream_close_full(*stream, FALSE);
 	o_stream_unref(stream);
 }
 
@@ -53,11 +62,7 @@
 
 void o_stream_close(struct ostream *stream)
 {
-	io_stream_close(&stream->real_stream->iostream);
-	stream->closed = TRUE;
-
-	if (stream->stream_errno == 0)
-		stream->stream_errno = EPIPE;
+	o_stream_close_full(stream, TRUE);
 }
 
 #undef o_stream_set_flush_callback
@@ -348,11 +353,14 @@
 	_stream->switch_ioloop(_stream);
 }
 
-static void o_stream_default_close(struct iostream_private *stream)
+static void o_stream_default_close(struct iostream_private *stream,
+				   bool close_parent)
 {
 	struct ostream_private *_stream = (struct ostream_private *)stream;
 
 	(void)o_stream_flush(&_stream->ostream);
+	if (close_parent && _stream->parent != NULL)
+		o_stream_close(_stream->parent);
 }
 
 static void o_stream_default_destroy(struct iostream_private *stream)
--- a/src/lib/ostream.h	Wed Mar 13 15:05:05 2013 +0200
+++ b/src/lib/ostream.h	Wed Mar 13 22:11:39 2013 +0200
@@ -47,7 +47,7 @@
 /* Return file descriptor for stream, or -1 if none is available. */
 int o_stream_get_fd(struct ostream *stream);
 
-/* o_stream_close() + o_stream_unref() */
+/* Close this stream (but not its parents) and unreference it. */
 void o_stream_destroy(struct ostream **stream);
 /* Reference counting. References start from 1, so calling o_stream_unref()
    destroys the stream if o_stream_ref() is never used. */
@@ -55,7 +55,8 @@
 /* Unreferences the stream and sets stream pointer to NULL. */
 void o_stream_unref(struct ostream **stream);
 
-/* Mark the stream closed. Nothing will be sent after this call. */
+/* Mark the stream and all of its parent streams closed. Nothing will be
+   sent after this call. */
 void o_stream_close(struct ostream *stream);
 
 /* Set IO_WRITE callback. Default will just try to flush the output and