glib r7991 - in trunk: . gio glib
- From: alexl svn gnome org
- To: svn-commits-list gnome org
- Subject: glib r7991 - in trunk: . gio glib
- Date: Mon, 16 Mar 2009 16:03:13 +0000 (UTC)
Author: alexl
Date: Mon Mar 16 16:03:13 2009
New Revision: 7991
URL: http://svn.gnome.org/viewvc/glib?rev=7991&view=rev
Log:
2009-03-16 Alexander Larsson <alexl redhat com>
Bug 575555 â Use fsync() when replacing files to avoid data loss on crash
* configure.in:
Look for fsync().
* glib/gfileutils.c:
(write_to_temp_file):
fsync temp file if destination file exists
2009-03-16 Alexander Larsson <alexl redhat com>
Bug 575555 â Use fsync() when replacing files to avoid data loss on crash
* glocalfileoutputstream.c:
(g_local_file_output_stream_close):
(_g_local_file_output_stream_replace):
fsync temp file before closing if replacing target file
Modified:
trunk/ChangeLog
trunk/configure.in
trunk/gio/ChangeLog
trunk/gio/glocalfileoutputstream.c
trunk/glib/gfileutils.c
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Mon Mar 16 16:03:13 2009
@@ -563,6 +563,7 @@
AC_CHECK_FUNCS(posix_memalign)
AC_CHECK_FUNCS(memalign)
AC_CHECK_FUNCS(valloc)
+AC_CHECK_FUNCS(fsync)
AC_CHECK_FUNCS(atexit on_exit)
Modified: trunk/gio/glocalfileoutputstream.c
==============================================================================
--- trunk/gio/glocalfileoutputstream.c (original)
+++ trunk/gio/glocalfileoutputstream.c Mon Mar 16 16:03:13 2009
@@ -69,6 +69,7 @@
char *original_filename;
char *backup_filename;
char *etag;
+ gboolean sync_on_close;
int fd;
};
@@ -190,6 +191,20 @@
file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
+#ifdef HAVE_FSYNC
+ if (file->priv->sync_on_close &&
+ fsync (file->priv->fd) != 0)
+ {
+ int errsv = errno;
+
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error writing to file: %s"),
+ g_strerror (errsv));
+ goto err_out;
+ }
+#endif
+
#ifdef G_OS_WIN32
/* Must close before renaming on Windows, so just do the close first
@@ -976,6 +991,7 @@
int mode;
int fd;
char *temp_file;
+ gboolean sync_on_close;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL;
@@ -986,6 +1002,7 @@
mode = 0600;
else
mode = 0666;
+ sync_on_close = FALSE;
/* If the file doesn't exist, create it */
fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
@@ -997,6 +1014,14 @@
flags, cancellable, error);
if (fd == -1)
return NULL;
+
+ /* If the final destination exists, we want to sync the newly written
+ * file to ensure the data is on disk when we rename over the destination.
+ * otherwise if we get a system crash we can lose both the new and the
+ * old file on some filesystems. (I.E. those that don't guarantee the
+ * data is written to the disk before the metadata.)
+ */
+ sync_on_close = TRUE;
}
else if (fd == -1)
{
@@ -1022,6 +1047,7 @@
stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
stream->priv->fd = fd;
+ stream->priv->sync_on_close = sync_on_close;
stream->priv->tmp_filename = temp_file;
if (create_backup)
stream->priv->backup_filename = create_backup_filename (filename);
Modified: trunk/glib/gfileutils.c
==============================================================================
--- trunk/glib/gfileutils.c (original)
+++ trunk/glib/gfileutils.c Mon Mar 16 16:03:13 2009
@@ -868,7 +868,7 @@
static gchar *
write_to_temp_file (const gchar *contents,
gssize length,
- const gchar *template,
+ const gchar *dest_file,
GError **err)
{
gchar *tmp_name;
@@ -880,7 +880,7 @@
retval = NULL;
- tmp_name = g_strdup_printf ("%s.XXXXXX", template);
+ tmp_name = g_strdup_printf ("%s.XXXXXX", dest_file);
errno = 0;
fd = create_temp_file (tmp_name, 0666);
@@ -942,11 +942,54 @@
goto out;
}
}
-
+
+ errno = 0;
+ if (fflush (file) != 0)
+ {
+ save_errno = errno;
+
+ g_set_error (err,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to write file '%s': fflush() failed: %s"),
+ display_name,
+ g_strerror (save_errno));
+
+ g_unlink (tmp_name);
+
+ goto out;
+ }
+
+#ifdef HAVE_FSYNC
+ errno = 0;
+ /* If the final destination exists, we want to sync the newly written
+ * file to ensure the data is on disk when we rename over the destination.
+ * otherwise if we get a system crash we can lose both the new and the
+ * old file on some filesystems. (I.E. those that don't guarantee the
+ * data is written to the disk before the metadata.)
+ */
+ if (g_file_test (dest_file, G_FILE_TEST_EXISTS) &&
+ fsync (fileno (file)) != 0)
+ {
+ save_errno = errno;
+
+ g_set_error (err,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to write file '%s': fsync() failed: %s"),
+ display_name,
+ g_strerror (save_errno));
+
+ g_unlink (tmp_name);
+
+ goto out;
+ }
+#endif
+
errno = 0;
if (fclose (file) == EOF)
{
- save_errno = 0;
+ save_errno = errno;
g_set_error (err,
G_FILE_ERROR,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]