In attachment a tentative of patch (but as it's already 2 am, I don't
guarantee anything).
--- leafpad-0.8.18.1_orig/src/file.c	2010-12-23 14:54:16.000000000 +0100
+++ leafpad-0.8.18.1/src/file.c	2016-11-23 00:45:53.000000000 +0100
@@ -180,6 +180,7 @@
 gint file_save_real(GtkWidget *view, FileInfo *fi)
 {
 	FILE *fp;
+	gint fd;
 	GtkTextIter start, end;
 	gchar *str, *cstr;
 	gsize rbytes, wbytes;
@@ -217,21 +218,60 @@
 		return -1;
 	}
 	
+	// opening the file in write mode (it will truncate the content!)
 	fp = fopen(fi->filename, "w");
 	if (!fp) {
 		run_dialog_message(gtk_widget_get_toplevel(view),
 			GTK_MESSAGE_ERROR, _("Can't open file to write"));
 		return -1;
 	}
-	if (fwrite(cstr, 1, wbytes, fp) != wbytes) {
+	
+	// write, and check all data could be flushed into the file stream
+	if ( (fwrite(cstr, 1, wbytes, fp) != wbytes) || fflush(fp) == EOF) {
 		run_dialog_message(gtk_widget_get_toplevel(view),
-			GTK_MESSAGE_ERROR, _("Can't write file"));
+			GTK_MESSAGE_ERROR, _("Failed to write all the data into file.\n"
+					"The file is probably truncated on disk.\n"));
 		return -1;
+
+		//	In theory to avoid such data loss, a pseudo atomic write strategy is :
+		//	write the data in a temp file on the same file system,
+		//	fflush, fsync, rename the temp file into the target file,
+		//	and fsync the parent directory too.
+		//
+		//	But that generate new questions:
+		//	  	is it always possible to create temporary file on the same file system?
+		//		is it easy to determine the current file system?
+		//		does the user have rights to create a temp file? and overwrite target file?
+		//	  	is there enough space on the file system for the temp file?
+		//
+		// see more at https://web.archive.org/web/20160420181318/http://lwn.net/Articles/457667/
 	}
+	g_free(cstr);
 	
+	// Try to ensure that data land on the device
+	fd = fileno(fp);
+	if( fd == -1 ) {
+		run_dialog_message(gtk_widget_get_toplevel(view),
+			GTK_MESSAGE_ERROR, _("Can't retrieve file descriptor"));
+		// return -1; // <- Don't abort and let's try to at least close the file
+	} else if (fsync(fd) == -1) {
+		run_dialog_message(gtk_widget_get_toplevel(view),
+			GTK_MESSAGE_ERROR, _("Can't sync file on device"));
+		// return -1; // <- Don't abort and let's try to at least close the file
+	}
+
+	// as we fflushed earlier, 
+	// fclose should not trigger a write of unflushed data anymore
+	// and probably not fail here
+	if (fclose(fp) == EOF) {
+		run_dialog_message(gtk_widget_get_toplevel(view),
+			GTK_MESSAGE_ERROR, _("Can't cleanly close file"));
+		return -1;
+	}
+
+	// notify the gtk layer that the data have been saved
+	// this will trigger a callback that can have side-effects if done before fclose(fp)
 	gtk_text_buffer_set_modified(buffer, FALSE);
-	fclose(fp);
-	g_free(cstr);
 	
 	return 0;
 }

Reply via email to