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; }