diff options
author | Ondrej Holy <oholy@redhat.com> | 2015-03-10 12:54:39 +0100 |
---|---|---|
committer | Ondrej Holy <oholy@redhat.com> | 2015-03-11 10:48:33 +0100 |
commit | f7f18bb6e7576672c2240c8ead8dfa4a2668d478 (patch) | |
tree | 1a1f770ead7d8d40a35e8e88f8f14d4e303feb0e /metadata | |
parent | a4f0bf37825378af9042eb6d95aa0d3d2b9df8d4 (diff) | |
download | gvfs-f7f18bb6e7576672c2240c8ead8dfa4a2668d478.tar.gz |
metadata: don't crash if tree write out failed
meta_tree_init can fail after we failed to write out an updated tree.
Backup corrupted file and start with empty tree to avoid consequent
crashes.
https://bugzilla.gnome.org/show_bug.cgi?id=598561
Diffstat (limited to 'metadata')
-rw-r--r-- | metadata/metatree.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/metadata/metatree.c b/metadata/metatree.c index 4c6d5f00..4964c682 100644 --- a/metadata/metatree.c +++ b/metadata/metatree.c @@ -643,6 +643,7 @@ meta_tree_refresh_locked (MetaTree *tree, gboolean force_reread) return TRUE; } +/* NB: The tree is uninitialized if FALSE is returned! */ gboolean meta_tree_refresh (MetaTree *tree) { @@ -2339,7 +2340,16 @@ meta_tree_flush_locked (MetaTree *tree) builder = meta_builder_new (); - copy_tree_to_builder (tree, tree->root, builder->root); + if (tree->root) + { + copy_tree_to_builder (tree, tree->root, builder->root); + } + else + { + /* It shouldn't happen, because tree is recovered in case of failed write + * out. Skip copy_tree_to_builder to avoid crash. */ + g_warning ("meta_tree_flush_locked: tree->root == NULL, possible data loss"); + } if (tree->journal) apply_journal_to_builder (tree, builder); @@ -2347,14 +2357,44 @@ meta_tree_flush_locked (MetaTree *tree) res = meta_builder_write (builder, meta_tree_get_filename (tree)); if (res) - /* Force re-read since we wrote a new file */ - res = meta_tree_refresh_locked (tree, TRUE); + { + /* Force re-read since we wrote a new file */ + res = meta_tree_refresh_locked (tree, TRUE); + + if (tree->root == NULL) + { + /* It shouldn't happen. We failed to write out an updated tree + * probably, therefore all the data are lost. Backup the file and + * reload the tree to avoid further crashes. */ + GTimeVal tv; + char *timestamp, *backup; + + g_get_current_time (&tv); + timestamp = g_time_val_to_iso8601 (&tv); + backup = g_strconcat (meta_tree_get_filename (tree), ".backup.", + timestamp, NULL); + g_rename (meta_tree_get_filename (tree), backup); + + g_warning ("meta_tree_flush_locked: tree->root == NULL, possible data loss\n" + "corrupted file was moved to: %s\n" + "(please make a comment on https://bugzilla.gnome.org/show_bug.cgi?id=598561 " + "and attach the corrupted file)", + backup); + + g_free (timestamp); + g_free (backup); + + res = meta_tree_refresh_locked (tree, TRUE); + g_assert (res); + } + } meta_builder_free (builder); return res; } +/* NB: The tree can be uninitialized if FALSE is returned! */ gboolean meta_tree_flush (MetaTree *tree) { |