[glib/glib-2-30] Don't close stream twice when splicing



commit 7b812c434388f0fc3cbbb67df5ab9f7db3a138ed
Author: Philip Withnall <philip tecnocode co uk>
Date:   Mon Sep 19 10:13:52 2011 +0200

    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
    (cherry picked from commit fe27bf003764e453cd15cab67e8a99fcda84db1d)

 gio/goutputstream.c |   88 ++++++++++++++++++++++++++++++--------------------
 1 files changed, 53 insertions(+), 35 deletions(-)
---
diff --git a/gio/goutputstream.c b/gio/goutputstream.c
index 8132caf..afe135c 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;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]