diff options
author | Philip Withnall <withnall@endlessm.com> | 2018-08-01 15:14:19 +0100 |
---|---|---|
committer | Philip Withnall <withnall@endlessm.com> | 2018-08-16 18:58:27 +0100 |
commit | 5ee749cd25f221c382fa4b9545cff62eefcb10cf (patch) | |
tree | d56e111398b8d9832f479b5614c5a41e0d529274 /service | |
parent | e960b50696b95f4b035787e9cbceaa549c172c91 (diff) | |
download | dconf-5ee749cd25f221c382fa4b9545cff62eefcb10cf.tar.gz |
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
Diffstat (limited to 'service')
-rw-r--r-- | service/dconf-gvdb-utils.c | 34 |
1 files changed, 33 insertions, 1 deletions
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; |