From fe27bf003764e453cd15cab67e8a99fcda84db1d Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Mon, 19 Sep 2011 10:13:52 +0200 Subject: [PATCH] Don't close stream twice when splicing Ensure that the output/target stream in a g_output_stream_splice_async() operation is marked as closed if G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET is passed to g_output_stream_splice_async(). This removes the possibility of local FDs being closed twice because the stream's not marked as closed. This is implemented by calling g_output_stream_close() from within g_output_stream_splice_async() instead of calling the stream's close_fn() directly. Closes: bgo#659324 --- gio/goutputstream.c | 88 +++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/gio/goutputstream.c b/gio/goutputstream.c index 8132caffc..afe135cb7 100644 --- a/gio/goutputstream.c +++ b/gio/goutputstream.c @@ -95,6 +95,9 @@ static void g_output_stream_real_close_async (GOutputStream *s static gboolean g_output_stream_real_close_finish (GOutputStream *stream, GAsyncResult *result, GError **error); +static gboolean _g_output_stream_close_internal (GOutputStream *stream, + GCancellable *cancellable, + GError **error); static void g_output_stream_finalize (GObject *object) @@ -459,9 +462,7 @@ g_output_stream_real_splice (GOutputStream *stream, if (flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET) { /* But write errors on close are bad! */ - if (class->close_fn && - !class->close_fn (stream, cancellable, error)) - res = FALSE; + res = _g_output_stream_close_internal (stream, cancellable, error); } if (res) @@ -470,6 +471,54 @@ g_output_stream_real_splice (GOutputStream *stream, return -1; } +/* Must always be called inside + * g_output_stream_set_pending()/g_output_stream_clear_pending(). */ +static gboolean +_g_output_stream_close_internal (GOutputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GOutputStreamClass *class; + gboolean res; + + if (stream->priv->closed) + return TRUE; + + class = G_OUTPUT_STREAM_GET_CLASS (stream); + + stream->priv->closing = TRUE; + + if (cancellable) + g_cancellable_push_current (cancellable); + + if (class->flush) + res = class->flush (stream, cancellable, error); + else + res = TRUE; + + if (!res) + { + /* flushing caused the error that we want to return, + * but we still want to close the underlying stream if possible + */ + if (class->close_fn) + class->close_fn (stream, cancellable, NULL); + } + else + { + res = TRUE; + if (class->close_fn) + res = class->close_fn (stream, cancellable, error); + } + + if (cancellable) + g_cancellable_pop_current (cancellable); + + stream->priv->closing = FALSE; + stream->priv->closed = TRUE; + + return res; +} /** * g_output_stream_close: @@ -514,49 +563,18 @@ g_output_stream_close (GOutputStream *stream, GCancellable *cancellable, GError **error) { - GOutputStreamClass *class; gboolean res; g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE); - class = G_OUTPUT_STREAM_GET_CLASS (stream); - if (stream->priv->closed) return TRUE; if (!g_output_stream_set_pending (stream, error)) return FALSE; - stream->priv->closing = TRUE; - - if (cancellable) - g_cancellable_push_current (cancellable); + res = _g_output_stream_close_internal (stream, cancellable, error); - if (class->flush) - res = class->flush (stream, cancellable, error); - else - res = TRUE; - - if (!res) - { - /* flushing caused the error that we want to return, - * but we still want to close the underlying stream if possible - */ - if (class->close_fn) - class->close_fn (stream, cancellable, NULL); - } - else - { - res = TRUE; - if (class->close_fn) - res = class->close_fn (stream, cancellable, error); - } - - if (cancellable) - g_cancellable_pop_current (cancellable); - - stream->priv->closing = FALSE; - stream->priv->closed = TRUE; g_output_stream_clear_pending (stream); return res; -- 2.34.1