[gtk+] iconcache: Ensure we don't lose data on power loss



commit 6c6b49392629a8ee2facafb66c8867a49a3e9036
Author: Colin Walters <walters verbum org>
Date:   Mon Nov 22 20:42:50 2010 +0100

    iconcache: Ensure we don't lose data on power loss
    
    fsync() should ensure our data hits disk; since corrupt icon
    caches break all apps, we need to ensure it's valid.
    
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=635307

 gtk/updateiconcache.c |   42 +++++++++++++++++++++++++++++++++++-------
 1 files changed, 35 insertions(+), 7 deletions(-)
---
diff --git a/gtk/updateiconcache.c b/gtk/updateiconcache.c
index 3b92701..7697a2c 100644
--- a/gtk/updateiconcache.c
+++ b/gtk/updateiconcache.c
@@ -1424,6 +1424,30 @@ validate_file (const gchar *file)
   return TRUE;
 }
 
+/**
+ * safe_fclose:
+ * @f: A FILE* stream, must have underlying fd
+ *
+ * Unix defaults for data preservation after system crash
+ * are unspecified, and many systems will eat your data
+ * in this situation unless you explicitly fsync().
+ *
+ * Returns: %TRUE on success, %FALSE on failure, and will set errno()
+ */
+static gboolean
+safe_fclose (FILE *f)
+{
+  int fd = fileno (f);
+  g_assert (fd >= 0);
+  if (fflush (f) == EOF)
+    return FALSE;
+  if (fsync (fd) < 0)
+    return FALSE;
+  if (fclose (f) == EOF)
+    return FALSE;
+  return TRUE;
+}
+
 static void
 build_cache (const gchar *path)
 {
@@ -1432,7 +1456,6 @@ build_cache (const gchar *path)
   gchar *bak_cache_path = NULL;
 #endif
   GHashTable *files;
-  gboolean retval;
   FILE *cache;
   struct stat path_stat, cache_stat;
   struct utimbuf utime_buf;
@@ -1490,17 +1513,22 @@ opentmp:
     }
     
   /* FIXME: Handle failure */
-  retval = write_file (cache, files, directories);
-  fclose (cache);
+  if (!write_file (cache, files, directories))
+    {
+      g_unlink (tmp_cache_path);
+      exit (1);
+    }
 
-  g_list_foreach (directories, (GFunc)g_free, NULL);
-  g_list_free (directories);
-  
-  if (!retval)
+  if (!safe_fclose (cache))
     {
+      g_printerr (_("Failed to write cache file: %s\n"), g_strerror (errno));
       g_unlink (tmp_cache_path);
       exit (1);
     }
+  cache = NULL;
+
+  g_list_foreach (directories, (GFunc)g_free, NULL);
+  g_list_free (directories);
 
   if (!validate_file (tmp_cache_path))
     {



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