diff libpurple/util.c @ 21172:33da7f2a30e4

Manually fflush() files written with purple_util_write_data_to_file, because apparently some filesystems (XFS) can and will leave bogus file contents if we don't. For systems which don't have fileno(), this involves closing and reopening the file.
author Ethan Blanton <elb@pidgin.im>
date Thu, 08 Nov 2007 19:49:12 +0000
parents 35b4f1dc4c8d
children abc909eeb580
line wrap: on
line diff
--- a/libpurple/util.c	Tue Nov 06 16:46:04 2007 +0000
+++ b/libpurple/util.c	Thu Nov 08 19:49:12 2007 +0000
@@ -2561,6 +2561,9 @@
 	FILE *file;
 	size_t real_size, byteswritten;
 	struct stat st;
+#ifndef HAVE_FILENO
+	int fd;
+#endif
 
 	purple_debug_info("util", "Writing file %s\n",
 					filename_full);
@@ -2595,6 +2598,19 @@
 	real_size = (size == -1) ? strlen(data) : (size_t) size;
 	byteswritten = fwrite(data, 1, real_size, file);
 
+#ifdef HAVE_FILENO
+	/* Apparently XFS (and possibly other filesystems) do not
+	 * guarantee that file data is flushed before file metadata,
+	 * so this procedure is insufficient without some flushage. */
+	if (fsync(fileno(file)) < 0) {
+		purple_debug_error("util", "Error syncing file contents for %s: %s\n",
+				   filename_temp, g_strerror(errno));
+		g_free(filename_temp);
+		fclose(file);
+		return FALSE;
+	}
+#endif
+    
 	/* Close file */
 	if (fclose(file) != 0)
 	{
@@ -2604,6 +2620,30 @@
 		return FALSE;
 	}
 
+#ifndef HAVE_FILENO
+	/* This is the same effect (we hope) as the HAVE_FILENO block
+	 * above, but for systems without fileno(). */
+	if ((fd = open(filename_temp, O_RDWR)) < 0) {
+		purple_debug_error("util", "Error opening file %s for flush: %s\n",
+				   filename_temp, g_strerror(errno));
+		g_free(filename_temp);
+		return FALSE;
+	}
+	if (fsync(fd) < 0) {
+		purple_debug_error("util", "Error syncing %s: %s\n",
+				   filename_temp, g_strerror(errno));
+		g_free(filename_temp);
+		close(fd);
+		return FALSE;
+	}
+	if (close(fd) < 0) {
+		purple_debug_error("util", "Error closing %s after sync: %s\n",
+				   filename_temp, g_strerror(errno));
+		g_free(filename_temp);
+		return FALSE;
+	}
+#endif
+
 	/* Ensure the file is the correct size */
 	if (byteswritten != real_size)
 	{