Backported from gedit/r5510 and r5511; handles SIGBUS properly which
might be triggered after I/O errors in mmap()ed files; see
GNOME #354046.

2007-02-24  Paolo Borelli  <pborelli@katamail.com>

       * gedit/gedit-document-loader.c: handle sigbus signal
       when acessing the mmaped file since it is fired in case
       of I/O error. This should fix #354046.

2007-02-24  Paolo Borelli  <pborelli@katamail.com>

       * gedit/gedit-document-loader.c: refactor how the
       encoding is fetched from metadata.

diff -Nur gedit-2.14.4/gedit/gedit-document-loader.c gedit-2.14.4.new/gedit/gedit-document-loader.c
--- gedit-2.14.4/gedit/gedit-document-loader.c	2006-04-20 19:05:25.000000000 +0200
+++ gedit-2.14.4.new/gedit/gedit-document-loader.c	2007-02-27 15:45:50.000000000 +0100
@@ -36,6 +36,8 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/mman.h>
+#include <signal.h>
+#include <setjmp.h>
 #include <string.h>
 #include <errno.h>
 
@@ -87,6 +89,7 @@
 
 	gchar                    *buffer;
 
+	const GeditEncoding      *metadata_encoding;
 	const GeditEncoding      *auto_detected_encoding;
 
 	GError                   *error;
@@ -249,6 +252,24 @@
 	return dl;						  
 }
 
+static const GeditEncoding *
+get_metadata_encoding (const gchar *uri)
+{
+	const GeditEncoding *enc;
+	gchar *charset;
+
+	charset = gedit_metadata_manager_get (uri, "encoding");
+
+	if (charset == NULL)
+		return NULL;
+
+	enc = gedit_encoding_get_from_charset (charset);
+
+	g_free (charset);
+
+	return enc;
+}
+
 static void
 insert_text_in_document (GeditDocumentLoader *loader,
 			 const gchar         *text,
@@ -311,29 +332,17 @@
 			/* Autodetecting the encoding: first try with the encoding
 			stored in the metadata, if any */
 
-			const GeditEncoding *enc;
-			gchar *charset;
-
-			charset = gedit_metadata_manager_get (loader->priv->uri, "encoding");
-
-			if (charset != NULL)
+			if (loader->priv->metadata_encoding != NULL)
 			{
-				enc = gedit_encoding_get_from_charset (charset);
+				converted_text = gedit_convert_to_utf8 (
+								file_contents,
+								file_size,
+								&loader->priv->metadata_encoding,
+								&new_len,
+								NULL);
 
-				if (enc != NULL)
-				{	
-					converted_text = gedit_convert_to_utf8 (
-									file_contents,
-									file_size,
-									&enc,
-									&new_len,
-									NULL);
-
-					if (converted_text != NULL)
-						loader->priv->auto_detected_encoding = enc;
-				}
-
-				g_free (charset);
+				if (converted_text != NULL)
+					loader->priv->auto_detected_encoding = loader->priv->metadata_encoding;
 			}
 		}
 
@@ -495,6 +504,18 @@
 
 #define MAX_MIME_SNIFF_SIZE 4096
 
+static sigjmp_buf mmap_env;
+static struct sigaction old_sigbusact;
+
+/* When we access the mmapped data we need to handle
+ * SIGBUS signal, which is emitted if there was an
+ * I/O error or if the file was truncated */
+static void
+mmap_sigbus_handler (int signo)
+{
+	siglongjmp (mmap_env, 0);
+}
+
 static gboolean
 load_local_file_real (GeditDocumentLoader *loader)
 {
@@ -532,6 +553,7 @@
 	{
 		gchar *mapped_file;
 		const gchar *mime_type;
+		struct sigaction sigbusact;
 
 		/* CHECK: should we lock the file */		
 		mapped_file = mmap (0, /* start */
@@ -540,7 +562,7 @@
 				    MAP_PRIVATE, /* flags */
 				    loader->priv->fd,
 				    0 /* offset */);
-				    
+
 		if (mapped_file == MAP_FAILED)
 		{
 			gedit_debug_message (DEBUG_SAVER, "mmap failed");
@@ -554,9 +576,37 @@
 
 			goto done;
 		}
-		
+
+		/* prepare to handle the SIGBUS signal which
+		 * may be fired when accessing the mmapped
+		 * data in case of I/O error.
+		 * See bug #354046.
+		 */
+		sigbusact.sa_handler = mmap_sigbus_handler;
+		sigemptyset (&sigbusact.sa_mask);
+		sigbusact.sa_flags = SA_RESETHAND;
+		sigaction (SIGBUS, &sigbusact, &old_sigbusact );
+
+		if (sigsetjmp (mmap_env, 1) != 0)
+		{
+			gedit_debug_message (DEBUG_LOADER, "SIGBUS during mmap");
+
+			g_set_error (&loader->priv->error,
+				     GEDIT_DOCUMENT_ERROR,
+				     GNOME_VFS_ERROR_IO,
+				     gnome_vfs_result_to_string (GNOME_VFS_ERROR_IO));
+
+			ret = munmap (mapped_file, loader->priv->info->size);
+			if (ret != 0)
+				g_warning ("File '%s' has not been correctly unmapped: %s",
+					   loader->priv->uri,
+					   strerror (errno));
+
+			goto done;
+		}
+
 		loader->priv->bytes_read = loader->priv->info->size;
-		
+
 		if (!update_document_contents (loader,
 					       mapped_file,
 					       loader->priv->info->size,
@@ -571,6 +621,9 @@
 			goto done;
 		}
 
+		/* restore the default sigbus handler */
+		sigaction (SIGBUS, &old_sigbusact, 0);
+
 		mime_type = gnome_vfs_get_mime_type_for_name_and_data (loader->priv->local_file_name,
 				mapped_file,
 				MIN (loader->priv->bytes_read, MAX_MIME_SNIFF_SIZE));
@@ -936,6 +989,11 @@
 
 	loader->priv->encoding = encoding;
 
+	if (encoding == NULL)
+	{
+		loader->priv->metadata_encoding = get_metadata_encoding (uri);
+	}
+
 	loader->priv->uri = g_strdup (uri);
 
 	local_path = gnome_vfs_get_local_path_from_uri (uri);
diff -Nur gedit-2.14.4/gedit/gedit-io-error-message-area.c gedit-2.14.4.new/gedit/gedit-io-error-message-area.c
--- gedit-2.14.4/gedit/gedit-io-error-message-area.c	2006-04-20 18:53:41.000000000 +0200
+++ gedit-2.14.4.new/gedit/gedit-io-error-message-area.c	2007-02-27 15:45:50.000000000 +0100
@@ -286,6 +286,16 @@
 		message_details = g_strdup (_("The file you are trying to open is not a regular file."));
 		break;
 
+	case GNOME_VFS_ERROR_IO:
+		/* FIXME: add a specific message when I are out
+		 * of string freeze
+
+		message_details = g_strdup ();
+
+		*/
+
+		break;
+
 	case GNOME_VFS_ERROR_GENERIC:
 		break;
 
