diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2011-09-19 10:13:52 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2011-09-19 10:13:52 +0200 |
commit | fe27bf003764e453cd15cab67e8a99fcda84db1d (patch) | |
tree | 3c03a721373c74cf112b5f95072586fd126a85ac /gio/goutputstream.c | |
parent | 808035666ac2f730b8819232f86cd3fac9de0d44 (diff) |
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
Diffstat (limited to 'gio/goutputstream.c')
-rw-r--r-- | gio/goutputstream.c | 88 |
1 files 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; |