changeset 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 4886667b0686
children 726f91be55ed
files configure.ac libpurple/util.c
diffstat 2 files changed, 64 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Tue Nov 06 16:46:04 2007 +0000
+++ b/configure.ac	Thu Nov 08 19:49:12 2007 +0000
@@ -233,6 +233,30 @@
 dnl FreeBSD doesn't have libdl, dlopen is provided by libc
 AC_CHECK_FUNC(dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")])
 
+AC_MSG_CHECKING(for fileno())
+AC_TRY_RUN([
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+	int fd;
+
+	fd = fileno(stdout);
+
+	return !(fd > 0);
+}
+], [
+	AC_MSG_RESULT(yes)
+	AC_DEFINE([HAVE_FILENO], [1],
+	          [Define to 1 if your stdio has int fileno(FILE *).])
+], [
+	AC_MSG_RESULT(no)
+], [
+	# Fallback for Cross Compiling...
+	# This will enable the compatibility code.
+	AC_MSG_RESULT(no)
+])
+
 AC_MSG_CHECKING(for the %z format string in strftime())
 AC_TRY_RUN([
 #ifdef HAVE_SYS_TIME_H
--- 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)
 	{