Index: libgnomeui/gnome-thumbnail.c
===================================================================
--- libgnomeui/gnome-thumbnail.c	(revision 5538)
+++ libgnomeui/gnome-thumbnail.c	(working copy)
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
 /*
  * gnome-thumbnail.c: Utilities for handling thumbnails
  *
@@ -37,6 +39,7 @@
 #include <stdio.h>
 
 #include <glib/gchecksum.h>
+#include <gio/gio.h>
 
 #define GDK_PIXBUF_ENABLE_BACKEND
 #include <gdk-pixbuf/gdk-pixbuf.h>
@@ -573,57 +576,109 @@
   GChecksum *checksum;
   guint8 digest[16];
   gsize digest_len = sizeof (digest);
+  GMount *mount;
+  char *rel_path;
+  char *mount_path;
+  GFile *f;
+  unsigned int n;
 
-  checksum = g_checksum_new (G_CHECKSUM_MD5);
-  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+  rel_path = NULL;
+  mount_path = NULL;
+  f = g_file_new_for_uri (uri);
+  mount = g_file_find_enclosing_mount (f, NULL, NULL);
+  if (mount != NULL)
+    {
+      GFile *mount_root;
+      mount_root = g_mount_get_root (mount);
+      mount_path = g_file_get_path (mount_root);
+      rel_path = g_file_get_relative_path (mount_root, f);
+      g_object_unref (mount_root);
+      g_object_unref (mount);
+    }
+  g_object_unref (f);
 
-  g_checksum_get_digest (checksum, digest, &digest_len);
-  g_assert (digest_len == 16);
-
   g_mutex_lock (priv->lock);
 
   gnome_thumbnail_factory_ensure_uptodate (factory);
-
-  if (g_hash_table_lookup_extended (priv->existing_thumbs,
-				    digest, NULL, &value))
+  
+  /* first try ~/.thumbnails; then .thumblocal on the mount */
+  for (n = 0; n < 2; n++)
     {
-      file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
-  
-      path = g_build_filename (g_get_home_dir (),
-			       ".thumbnails",
-			       (priv->size == GNOME_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
-			       file,
-			       NULL);
-      g_free (file);
+      switch (n)
+        {          
+        default:
+        case 0:
+          checksum = g_checksum_new (G_CHECKSUM_MD5);
+          g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+          g_checksum_get_digest (checksum, digest, &digest_len);
+          g_assert (digest_len == 16);
+          if (!g_hash_table_lookup_extended (priv->existing_thumbs, digest, NULL, &value))
+            value = NULL;
+          file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+          g_checksum_free (checksum);
 
+          path = g_build_filename (g_get_home_dir (),
+                                   ".thumbnails",
+                                   (priv->size == GNOME_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+                                   file,
+                                   NULL);
+          g_free (file);
+          break;
+
+        case 1:
+          if (rel_path == NULL)
+            {
+              continue;
+            }
+
+          checksum = g_checksum_new (G_CHECKSUM_MD5);
+          g_checksum_update (checksum, (const guchar *) rel_path, strlen (rel_path));
+          g_checksum_get_digest (checksum, digest, &digest_len);
+          g_assert (digest_len == 16);
+          if (!g_hash_table_lookup_extended (priv->existing_thumbs, digest, NULL, &value))
+            value = NULL;
+          file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+          g_checksum_free (checksum);
+
+          path = g_build_filename (mount_path,
+                                   ".thumblocal",
+                                   (priv->size == GNOME_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+                                   file,
+                                   NULL);
+          g_free (file);
+          break;
+        }
+      
       if (value == NULL)
-	{
-	  info = load_thumbnail_info (path);
-	  if (info)
-	    {
-	      g_hash_table_insert (priv->existing_thumbs,
+        {
+          info = load_thumbnail_info (path);
+          if (info)
+            {
+              g_hash_table_insert (priv->existing_thumbs,
                                    g_memdup (digest, sizeof (digest)),
                                    info);
-	    }
-	}
+            }
+        }
       else
-	info = value;
+        info = value;
 
       if (info &&
-	  info->mtime == mtime &&
-	  strcmp (info->uri, uri) == 0)
-	{
-	  g_mutex_unlock (priv->lock);
-          g_checksum_free (checksum);
-	  return path;
-	}
+          info->mtime == mtime &&
+          strcmp (info->uri, rel_path != NULL ? rel_path : uri) == 0)
+        {
+          g_mutex_unlock (priv->lock);
+          g_free (rel_path);
+          g_free (mount_path);
+          return path;
+        }
       
       g_free (path);
     }
 
   g_mutex_unlock (priv->lock);
   
-  g_checksum_free (checksum);
+  g_free (rel_path);
+  g_free (mount_path);
 
   return NULL;
 }
@@ -760,7 +815,7 @@
   /* Don't thumbnail thumbnails */
   if (uri &&
       strncmp (uri, "file:/", 6) == 0 &&
-      strstr (uri, "/.thumbnails/") != NULL)
+      (strstr (uri, "/.thumbnails/") != NULL || strstr (uri, "/.thumblocal/") != NULL))
     return FALSE;
   
   if (mime_type != NULL &&
@@ -980,17 +1035,16 @@
 }
 
 static gboolean
-make_thumbnail_dirs (GnomeThumbnailFactory *factory)
+make_thumbnail_dirs (GnomeThumbnailFactory *factory, const char *thumbnail_dir)
 {
-  char *thumbnail_dir;
   char *image_dir;
   gboolean res;
 
   res = FALSE;
 
-  thumbnail_dir = g_build_filename (g_get_home_dir (),
-				    ".thumbnails",
-				    NULL);
+  g_return_val_if_fail (factory != NULL, FALSE);
+  g_return_val_if_fail (thumbnail_dir != NULL, FALSE);
+
   if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
     {
       g_mkdir (thumbnail_dir, 0700);
@@ -1006,7 +1060,6 @@
       res = TRUE;
     }
 
-  g_free (thumbnail_dir);
   g_free (image_dir);
   
   return res;
@@ -1023,16 +1076,16 @@
   res = FALSE;
 
   thumbnail_dir = g_build_filename (g_get_home_dir (),
-				    ".thumbnails",
-				    NULL);
+                                    ".thumbnails",
+                                    NULL);
   if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
     {
       g_mkdir (thumbnail_dir, 0700);
       res = TRUE;
     }
 
-  fail_dir = g_build_filename (thumbnail_dir,
-			       "fail",
+  fail_dir = g_build_filename (g_get_home_dir (),
+                               ".thumbnails/fail",
 			       NULL);
   if (!g_file_test (fail_dir, G_FILE_TEST_IS_DIR))
     {
@@ -1056,7 +1109,6 @@
   return res;
 }
 
-
 /**
  * gnome_thumbnail_factory_save_thumbnail:
  * @factory: a #GnomeThumbnailFactory
@@ -1089,10 +1141,55 @@
   GChecksum *checksum;
   guint8 digest[16];
   gsize digest_len = sizeof (digest);
+  char *thumbdir;
+  GMount *mount;
+  GFile *f;
+  char *rel_path;
 
+  /* SECURITY: Always use .thumblocal on the mount if it's encrypted; otherwise
+   *           we're gonna be leaking encrypted data in $HOME
+   */
+  thumbdir = NULL;
+  rel_path = NULL;
+  f = g_file_new_for_uri (uri);
+  mount = g_file_find_enclosing_mount (f, NULL, NULL);
+  if (mount != NULL)
+    {
+      GFile *mount_root;
+      char *mount_path;
+
+      mount_root = g_mount_get_root (mount);
+
+      mount_path = g_file_get_path (mount_root);
+      if (mount_path != NULL && 
+          g_mount_is_encrypted (mount) &&
+          strcmp (mount_path, g_get_home_dir()) != 0) /* avoid .thumblocal on encrypted $HOME */
+        {
+          thumbdir = g_build_filename (mount_path, ".thumblocal", NULL);
+          rel_path = g_file_get_relative_path (mount_root, f);
+        }
+
+      g_object_unref (mount_root);
+      g_object_unref (mount);
+      g_free (mount_path);
+    }
+  g_object_unref (f);
+  if (thumbdir == NULL)
+    {
+      thumbdir = g_build_filename (g_get_home_dir (), ".thumbnails", NULL);
+    }
+
   checksum = g_checksum_new (G_CHECKSUM_MD5);
-  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
 
+  if (rel_path != NULL)
+    {
+      g_checksum_update (checksum, (const guchar *) rel_path, strlen (rel_path));
+    }
+  else
+    {
+      g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+    }
+
   g_checksum_get_digest (checksum, digest, &digest_len);
   g_assert (digest_len == 16);
 
@@ -1103,9 +1200,10 @@
   g_mutex_unlock (priv->lock);
 
   file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  g_checksum_free (checksum);
+
   
-  dir = g_build_filename (g_get_home_dir (),
-			  ".thumbnails",
+  dir = g_build_filename (thumbdir,
 			  (priv->size == GNOME_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
 			  NULL);
   
@@ -1118,7 +1216,7 @@
 
   tmp_fd = g_mkstemp (tmp_path);
   if (tmp_fd == -1 &&
-      make_thumbnail_dirs (factory))
+      make_thumbnail_dirs (factory, thumbdir))
     {
       g_free (tmp_path);
       tmp_path = g_strconcat (path, ".XXXXXX", NULL);
@@ -1131,6 +1229,8 @@
       g_free (dir);
       g_free (tmp_path);
       g_free (path);
+      g_free (thumbdir);
+      g_free (rel_path);
       return;
     }
   close (tmp_fd);
@@ -1145,7 +1245,7 @@
 				 "png", NULL,
 				 "tEXt::Thumb::Image::Width", width,
 				 "tEXt::Thumb::Image::Height", height,
-				 "tEXt::Thumb::URI", uri,
+				 "tEXt::Thumb::URI", rel_path != NULL ? rel_path : uri,
 				 "tEXt::Thumb::MTime", mtime_str,
 				 "tEXt::Software", "GNOME::ThumbnailFactory",
 				 NULL);
@@ -1153,11 +1253,10 @@
     saved_ok  = gdk_pixbuf_save (thumbnail,
 				 tmp_path,
 				 "png", NULL,
-				 "tEXt::Thumb::URI", uri,
+				 "tEXt::Thumb::URI", rel_path != NULL ? rel_path : uri,
 				 "tEXt::Thumb::MTime", mtime_str,
 				 "tEXt::Software", "GNOME::ThumbnailFactory",
 				 NULL);
-    
 
   if (saved_ok)
     {
@@ -1192,6 +1291,8 @@
   g_free (dir);
   g_free (path);
   g_free (tmp_path);
+  g_free (thumbdir);
+  g_free (rel_path);
 }
 
 /**
@@ -1237,9 +1338,10 @@
   g_mutex_unlock (priv->lock);
 
   file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  g_checksum_free (checksum);
   
   dir = g_build_filename (g_get_home_dir (),
-			  ".thumbnails/fail",
+                          ".thumbnails/fail",
 			  factory->priv->application,
 			  NULL);
   
