[gimp] app, libgimpconfig: make various usage of g_file_replace() safer.



commit 613bf7c5abaa58ec9148fead136f8a23cf166954
Author: Jehan <jehan girinstud io>
Date:   Mon Nov 26 15:40:38 2018 +0100

    app, libgimpconfig: make various usage of g_file_replace() safer.
    
    When an error occurs, we want to prevent overwriting any previous
    version of the file by incomplete contents. So run
    g_output_stream_close() with a cancelled GCancellable to do so.
    See also discussion in #2565.

 app/core/gimp-internal-data.c       | 26 +++++++++++++++++---------
 app/core/gimp-tags.c                | 16 ++++++++++++++--
 app/core/gimpdata.c                 | 26 +++++++++++++++++---------
 app/core/gimpgradient-save.c        |  8 ++++++++
 app/core/gimptagcache.c             | 15 +++++++++++++--
 app/gui/themes.c                    | 17 +++++++++++++++--
 app/pdb/gimppdb-query.c             |  7 +++++++
 app/tools/gimpfiltertool-settings.c |  8 ++++++++
 app/vectors/gimpvectors-export.c    |  8 ++++++++
 app/widgets/gimpdashboard.c         | 20 +++++++++++++++++++-
 app/widgets/gimptextbuffer.c        |  8 ++++++++
 libgimpconfig/gimpconfigwriter.c    |  7 +++++++
 12 files changed, 141 insertions(+), 25 deletions(-)
---
diff --git a/app/core/gimp-internal-data.c b/app/core/gimp-internal-data.c
index d07f309973..6653946f6e 100644
--- a/app/core/gimp-internal-data.c
+++ b/app/core/gimp-internal-data.c
@@ -288,17 +288,25 @@ gimp_internal_data_save_data_file (Gimp                        *gimp,
           success = FALSE;
         }
     }
-  else if (error && *error)
-    {
-      g_prefix_error (error,
-                      _("Error saving '%s': "),
-                      gimp_file_get_utf8_name (file));
-    }
   else
     {
-      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_WRITE,
-                   _("Error saving '%s'"),
-                   gimp_file_get_utf8_name (file));
+      GCancellable *cancellable = g_cancellable_new ();
+
+      g_cancellable_cancel (cancellable);
+      if (error && *error)
+        {
+          g_prefix_error (error,
+                          _("Error saving '%s': "),
+                          gimp_file_get_utf8_name (file));
+        }
+      else
+        {
+          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_WRITE,
+                       _("Error saving '%s'"),
+                       gimp_file_get_utf8_name (file));
+        }
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
     }
 
   g_object_unref (output);
diff --git a/app/core/gimp-tags.c b/app/core/gimp-tags.c
index 75d39e8607..5efedb9648 100644
--- a/app/core/gimp-tags.c
+++ b/app/core/gimp-tags.c
@@ -138,12 +138,24 @@ gimp_tags_user_install (void)
   else if (! g_output_stream_write_all (output,
                                         tags_installer.buf->str,
                                         tags_installer.buf->len,
-                                        NULL, NULL, &error) ||
-           ! g_output_stream_close (output, NULL, &error))
+                                        NULL, NULL, &error))
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       g_printerr (_("Error writing '%s': %s"),
                   gimp_file_get_utf8_name (file), error->message);
       result = FALSE;
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
+    }
+  else if (! g_output_stream_close (output, NULL, &error))
+    {
+      g_printerr (_("Error closing '%s': %s"),
+                  gimp_file_get_utf8_name (file), error->message);
+      result = FALSE;
     }
 
   if (output)
diff --git a/app/core/gimpdata.c b/app/core/gimpdata.c
index 4d7388d86f..d8ee11ba07 100644
--- a/app/core/gimpdata.c
+++ b/app/core/gimpdata.c
@@ -592,17 +592,25 @@ gimp_data_save (GimpData  *data,
                   success = FALSE;
                 }
             }
-          else if (error && *error)
-            {
-              g_prefix_error (error,
-                              _("Error saving '%s': "),
-                              gimp_file_get_utf8_name (private->file));
-            }
           else
             {
-              g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_WRITE,
-                           _("Error saving '%s'"),
-                           gimp_file_get_utf8_name (private->file));
+              GCancellable *cancellable = g_cancellable_new ();
+
+              g_cancellable_cancel (cancellable);
+              if (error && *error)
+                {
+                  g_prefix_error (error,
+                                  _("Error saving '%s': "),
+                                  gimp_file_get_utf8_name (private->file));
+                }
+              else
+                {
+                  g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_WRITE,
+                               _("Error saving '%s'"),
+                               gimp_file_get_utf8_name (private->file));
+                }
+              g_output_stream_close (output, cancellable, NULL);
+              g_object_unref (cancellable);
             }
 
           g_object_unref (output);
diff --git a/app/core/gimpgradient-save.c b/app/core/gimpgradient-save.c
index 9cd9423a95..510f2d68db 100644
--- a/app/core/gimpgradient-save.c
+++ b/app/core/gimpgradient-save.c
@@ -207,13 +207,21 @@ gimp_gradient_save_pov (GimpGradient  *gradient,
   if (! g_output_stream_write_all (output, string->str, string->len,
                                    NULL, NULL, &my_error))
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_WRITE,
                    _("Writing POV file '%s' failed: %s"),
                    gimp_file_get_utf8_name (file),
                    my_error->message);
       g_clear_error (&my_error);
       g_string_free (string, TRUE);
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
       g_object_unref (output);
+
       return FALSE;
     }
 
diff --git a/app/core/gimptagcache.c b/app/core/gimptagcache.c
index ab508c0243..a0e4534d8f 100644
--- a/app/core/gimptagcache.c
+++ b/app/core/gimptagcache.c
@@ -430,11 +430,22 @@ gimp_tag_cache_save (GimpTagCache *cache)
       g_printerr ("%s\n", error->message);
     }
   else if (! g_output_stream_write_all (output, buf->str, buf->len,
-                                        NULL, NULL, &error) ||
-           ! g_output_stream_close (output, NULL, &error))
+                                        NULL, NULL, &error))
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       g_printerr (_("Error writing '%s': %s\n"),
                   gimp_file_get_utf8_name (file), error->message);
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
+    }
+  else if (! g_output_stream_close (output, NULL, &error))
+    {
+      g_printerr (_("Error closing '%s': %s\n"),
+                  gimp_file_get_utf8_name (file), error->message);
     }
 
   if (output)
diff --git a/app/gui/themes.c b/app/gui/themes.c
index 73fb832d36..2894a66298 100644
--- a/app/gui/themes.c
+++ b/app/gui/themes.c
@@ -285,13 +285,26 @@ themes_apply_theme (Gimp        *gimp,
              "/* end of theme.css */\n",
              gimp_file_get_utf8_name (css_user),
              esc_css_theme,
-             esc_css_user) ||
-          ! g_output_stream_close (output, NULL, &error))
+             esc_css_user))
         {
+          GCancellable *cancellable = g_cancellable_new ();
+
           gimp_message (gimp, NULL, GIMP_MESSAGE_ERROR,
                         _("Error writing '%s': %s"),
                         gimp_file_get_utf8_name (theme_css), error->message);
           g_clear_error (&error);
+
+          /* Cancel the overwrite initiated by g_file_replace(). */
+          g_cancellable_cancel (cancellable);
+          g_output_stream_close (output, cancellable, NULL);
+          g_object_unref (cancellable);
+        }
+      else if (! g_output_stream_close (output, NULL, &error))
+        {
+          gimp_message (gimp, NULL, GIMP_MESSAGE_ERROR,
+                        _("Error closing '%s': %s"),
+                        gimp_file_get_utf8_name (theme_css), error->message);
+          g_clear_error (&error);
         }
 
       g_free (esc_css_theme);
diff --git a/app/pdb/gimppdb-query.c b/app/pdb/gimppdb-query.c
index 7b0ca7e34e..00689faa9b 100644
--- a/app/pdb/gimppdb-query.c
+++ b/app/pdb/gimppdb-query.c
@@ -136,10 +136,17 @@ gimp_pdb_dump (GimpPDB  *pdb,
 
   if (pdb_dump.error)
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       g_set_error (error, pdb_dump.error->domain, pdb_dump.error->code,
                    _("Writing PDB file '%s' failed: %s"),
                    gimp_file_get_utf8_name (file), pdb_dump.error->message);
       g_clear_error (&pdb_dump.error);
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (pdb_dump.output, cancellable, NULL);
+      g_object_unref (cancellable);
       g_object_unref (pdb_dump.output);
 
       return FALSE;
diff --git a/app/tools/gimpfiltertool-settings.c b/app/tools/gimpfiltertool-settings.c
index 5ae5fadb86..c8364ff836 100644
--- a/app/tools/gimpfiltertool-settings.c
+++ b/app/tools/gimpfiltertool-settings.c
@@ -221,6 +221,8 @@ gimp_filter_tool_settings_export (GimpSettingsBox *box,
 
   if (! tool_class->settings_export (filter_tool, output, &error))
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       gimp_message (GIMP_TOOL (filter_tool)->tool_info->gimp,
                     G_OBJECT (gimp_tool_gui_get_dialog (filter_tool->gui)),
                     GIMP_MESSAGE_ERROR,
@@ -228,7 +230,13 @@ gimp_filter_tool_settings_export (GimpSettingsBox *box,
                     gimp_file_get_utf8_name (file),
                     error->message);
       g_clear_error (&error);
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
       g_object_unref (output);
+
       return FALSE;
     }
 
diff --git a/app/vectors/gimpvectors-export.c b/app/vectors/gimpvectors-export.c
index 89e929c8e4..f8a33e80a8 100644
--- a/app/vectors/gimpvectors-export.c
+++ b/app/vectors/gimpvectors-export.c
@@ -83,12 +83,20 @@ gimp_vectors_export_file (GimpImage    *image,
   if (! g_output_stream_write_all (output, string->str, string->len,
                                    NULL, NULL, &my_error))
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       g_set_error (error, my_error->domain, my_error->code,
                    _("Writing SVG file '%s' failed: %s"),
                    gimp_file_get_utf8_name (file), my_error->message);
       g_clear_error (&my_error);
       g_string_free (string, TRUE);
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (output, cancellable, NULL);
+      g_object_unref (cancellable);
       g_object_unref (output);
+
       return FALSE;
     }
 
diff --git a/app/widgets/gimpdashboard.c b/app/widgets/gimpdashboard.c
index 7bc03f6c1a..a9c8bb9197 100644
--- a/app/widgets/gimpdashboard.c
+++ b/app/widgets/gimpdashboard.c
@@ -4344,8 +4344,15 @@ gimp_dashboard_log_start_recording (GimpDashboard  *dashboard,
 
   if (priv->log_error)
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
       gimp_backtrace_stop ();
 
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (priv->log_output, cancellable, NULL);
+      g_object_unref (cancellable);
+
       g_clear_object (&priv->log_output);
 
       g_propagate_error (error, priv->log_error);
@@ -4422,7 +4429,18 @@ gimp_dashboard_log_stop_recording (GimpDashboard  *dashboard,
     gimp_backtrace_stop ();
 
   if (! priv->log_error)
-    g_output_stream_close (priv->log_output, NULL, &priv->log_error);
+    {
+      g_output_stream_close (priv->log_output, NULL, &priv->log_error);
+    }
+  else
+    {
+      GCancellable *cancellable = g_cancellable_new ();
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (priv->log_output, cancellable, NULL);
+      g_object_unref (cancellable);
+    }
 
   g_clear_object (&priv->log_output);
 
diff --git a/app/widgets/gimptextbuffer.c b/app/widgets/gimptextbuffer.c
index 88cd2aa1c0..4e02b4f3dd 100644
--- a/app/widgets/gimptextbuffer.c
+++ b/app/widgets/gimptextbuffer.c
@@ -1764,12 +1764,20 @@ gimp_text_buffer_save (GimpTextBuffer *buffer,
       if (! g_output_stream_write_all (output, text_contents, text_length,
                                        NULL, NULL, &my_error))
         {
+          GCancellable *cancellable = g_cancellable_new ();
+
           g_set_error (error, my_error->domain, my_error->code,
                        _("Writing text file '%s' failed: %s"),
                        gimp_file_get_utf8_name (file), my_error->message);
           g_clear_error (&my_error);
           g_free (text_contents);
+
+          /* Cancel the overwrite initiated by g_file_replace(). */
+          g_cancellable_cancel (cancellable);
+          g_output_stream_close (output, cancellable, NULL);
+          g_object_unref (cancellable);
           g_object_unref (output);
+
           return FALSE;
         }
 
diff --git a/libgimpconfig/gimpconfigwriter.c b/libgimpconfig/gimpconfigwriter.c
index 23bf54663e..bac83f3667 100644
--- a/libgimpconfig/gimpconfigwriter.c
+++ b/libgimpconfig/gimpconfigwriter.c
@@ -760,6 +760,13 @@ gimp_config_writer_close_output (GimpConfigWriter  *writer,
 
   if (writer->error)
     {
+      GCancellable *cancellable = g_cancellable_new ();
+
+      /* Cancel the overwrite initiated by g_file_replace(). */
+      g_cancellable_cancel (cancellable);
+      g_output_stream_close (writer->output, cancellable, NULL);
+      g_object_unref (cancellable);
+
       g_object_unref (writer->output);
       writer->output = NULL;
 


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