[dconf: 1/9] service: Allow opening corrupt GVDB files when writing



commit 5ee749cd25f221c382fa4b9545cff62eefcb10cf
Author: Philip Withnall <withnall endlessm com>
Date:   Wed Aug 1 15:14:19 2018 +0100

    service: Allow opening corrupt GVDB files when writing
    
    If a GVDB file cannot be opened due to being corrupt, move it out of the
    way, warn, and open a new blank database instead.
    
    This prevents the situation where a corrupt database stops the entire
    desktop session from loading.
    
    Note that the dconf_gvdb_utils_read_file() code path is only taken
    inside DConfWriter. The DConf engine sources (such as
    dconf-engine-source-system.c) open the GVDB tables separately, and
    already all handle errors gracefully.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    
    https://gitlab.gnome.org/GNOME/glib/issues/1454

 service/dconf-gvdb-utils.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)
---
diff --git a/service/dconf-gvdb-utils.c b/service/dconf-gvdb-utils.c
index 099a9f3..fdd90e2 100644
--- a/service/dconf-gvdb-utils.c
+++ b/service/dconf-gvdb-utils.c
@@ -26,6 +26,9 @@
 #include "../gvdb/gvdb-builder.h"
 #include "../gvdb/gvdb-reader.h"
 
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
 #include <string.h>
 
 DConfChangeset *
@@ -57,7 +60,36 @@ dconf_gvdb_utils_read_file (const gchar  *filename,
   /* Otherwise, we should report errors to prevent ourselves from
    * overwriting the database in other situations...
    */
-  if (my_error)
+  if (g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_INVAL))
+    {
+      /* Move the database to a backup file, warn and continue with a new
+       * database. The alternative is erroring out and exiting the daemon,
+       * which leaves the user’s session essentially unusable.
+       *
+       * The code to find an unused backup filename is racy, but this is an
+       * error handling path. Who cares. */
+      g_autofree gchar *backup_filename = NULL;
+      guint i;
+
+      for (i = 0;
+           i < G_MAXUINT &&
+           (backup_filename == NULL || g_file_test (backup_filename, G_FILE_TEST_EXISTS));
+           i++)
+        {
+          g_free (backup_filename);
+          backup_filename = g_strdup_printf ("%s~%u", filename, i);
+        }
+
+      if (g_rename (filename, backup_filename) != 0)
+        g_warning ("Error renaming corrupt database from ‘%s’ to ‘%s’: %s",
+                   filename, backup_filename, g_strerror (errno));
+      else
+        g_warning ("Database ‘%s’ was corrupt: moved it to ‘%s’ and created an empty replacement",
+                   filename, backup_filename);
+
+      g_clear_error (&my_error);
+    }
+  else if (my_error)
     {
       g_propagate_prefixed_error (error, my_error, "Cannot open dconf database: ");
       return NULL;


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