Index: monitor/gphoto2/ggphoto2volume.c
===================================================================
--- monitor/gphoto2/ggphoto2volume.c	(revision 2042)
+++ monitor/gphoto2/ggphoto2volume.c	(working copy)
@@ -260,21 +260,28 @@
   g_return_val_if_fail (pool != NULL, NULL);
   g_return_val_if_fail (foreign_mount_root != NULL, NULL);
 
+#if 0
   if (!hal_device_has_capability (device, "camera") ||
       (hal_device_has_capability (device, "portable_audio_player") &&
-       hal_device_get_property_bool (device, "camera.libgphoto2.support")))
+       hal_device_get_property_bool (device, "camera.libgphoto2.support"))) {
+       	  g_message ("not audio player, photo, or camera");
     return NULL;
-
+  }
+#endif
   /* OK, so we abuse storage_udi and drive_device for the USB main
    * device that holds this interface...
    */
   storage_udi = hal_device_get_property_string (device, "info.parent");
-  if (storage_udi == NULL)
+  if (storage_udi == NULL) {
+  	  g_message ("no parent");
     return NULL;
+  }
 
   drive_device = hal_pool_get_device_by_udi (pool, storage_udi);
-  if (drive_device == NULL)
+  if (drive_device == NULL) {
+  	  g_message ("no drive device");
     return NULL;
+  }
 
   /* TODO: other OS'es? Will address this with DK aka HAL 2.0 */
   device_path = hal_device_get_property_string (drive_device, "linux.device_file");
Index: monitor/gphoto2/ggphoto2volumemonitor.c
===================================================================
--- monitor/gphoto2/ggphoto2volumemonitor.c	(revision 2042)
+++ monitor/gphoto2/ggphoto2volumemonitor.c	(working copy)
@@ -537,24 +537,37 @@
       usb_bus_num = hal_device_get_property_int (d, "usb.bus_number");
       usb_device_num = hal_device_get_property_int (d, "usb.linux.device_number");
 
-      uri = g_strdup_printf ("gphoto2://[usb:%03d,%03d]", usb_bus_num, usb_device_num);
-      /*g_warning ("uri is '%s'", uri);*/
-      foreign_mount_root = g_file_new_for_uri (uri);
-      g_free (uri);
+      //FIXME get the heads for real!
 
-      udi = hal_device_get_udi (d);
-      /*g_warning ("camera adding %s", udi);*/
+      int num_heads = 2, i;
+      char *heads_root[] = { "store_00010001", "store_00020001" };
+      for (i = 0; i < num_heads; i++)
+        {
+          uri = g_strdup_printf ("gphoto2://[usb:%03d,%03d,%s]", usb_bus_num, usb_device_num, heads_root[i]);
 
-      volume = g_gphoto2_volume_new (G_VOLUME_MONITOR (monitor),
-                                     d,
-                                     monitor->pool,
-                                     foreign_mount_root);
-      g_object_unref (foreign_mount_root);
-      if (volume != NULL)
-        {
-          monitor->camera_volumes = g_list_prepend (monitor->camera_volumes, volume);
-          *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
-        }
+	  /*g_warning ("uri is '%s'", uri);*/
+	  foreign_mount_root = g_file_new_for_uri (uri);
+//	  g_free (uri);
+
+	  udi = hal_device_get_udi (d);
+	  /*g_warning ("camera adding %s", udi);*/
+
+	  volume = g_gphoto2_volume_new (G_VOLUME_MONITOR (monitor),
+					 d,
+					 monitor->pool,
+					 foreign_mount_root);
+	  g_object_unref (foreign_mount_root);
+	  if (volume != NULL)
+            {
+            	    g_message ("added volume for uri %s", uri);
+		    monitor->camera_volumes = g_list_prepend (monitor->camera_volumes, volume);
+		    *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+	    }
+	  else
+	    {
+	    	    g_message ("didn't add volume for uri %s", uri);
+	    }
+	}
     }
 
   g_list_free (added);
Index: daemon/gphoto2.mount.in
===================================================================
--- daemon/gphoto2.mount.in	(revision 2042)
+++ daemon/gphoto2.mount.in	(working copy)
@@ -2,3 +2,4 @@
 Type=gphoto2
 Exec=@libexecdir@/gvfsd-gphoto2
 AutoMount=false
+DBusName=org.gtk.vfs.mountpoint.gphoto2
Index: daemon/daemon-main.c
===================================================================
--- daemon/daemon-main.c	(revision 2042)
+++ daemon/daemon-main.c	(working copy)
@@ -65,6 +65,12 @@
       dbus_error_free (&derror);
       exit (1);
     }
+
+  GLogLevelFlags fatal_mask;
+
+  fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+  fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+  g_log_set_always_fatal (fatal_mask);
 }
 
 void
Index: daemon/Makefile.am
===================================================================
--- daemon/Makefile.am	(revision 2042)
+++ daemon/Makefile.am	(working copy)
@@ -354,6 +354,7 @@
 
 gvfsd_gphoto2_CPPFLAGS = \
 	-DBACKEND_HEADER=gvfsbackendgphoto2.h \
+	-DMOUNTABLE_DBUS_NAME=org.gtk.vfs.mountpoint.gphoto2 \
 	-DDEFAULT_BACKEND_TYPE=gphoto2 \
 	-DMAX_JOB_THREADS=1 \
 	$(GPHOTO2_CFLAGS) $(HAL_CFLAGS) \
Index: daemon/gvfsbackendgphoto2.c
===================================================================
--- daemon/gvfsbackendgphoto2.c	(revision 2042)
+++ daemon/gvfsbackendgphoto2.c	(working copy)
@@ -146,13 +146,6 @@
  *        use replace() directly instead of fooling around with ~-style
  *        backup files
  *
- *  - support for multiple storage heads
- *    - need a device that supports this
- *    - should be different mounts so need to infect GHalVolumeMonitor with libgphoto2
- *    - probably not a huge priority to add
- *    - might help properly resolve the hack we're doing in ensure_ignore_prefix()
- *      - http://bugzilla.gnome.org/show_bug.cgi?id=520123
- *
  *  - adding a payload cache don't make much sense as libgphoto2 has a LRU cache already
  *    - (see comment in the do_close_write() function)
  *
@@ -168,16 +161,30 @@
  *    
  */
 
+struct Gphoto2Device
+{
+  GPContext *context;
+  Camera *camera;
+  volatile int refcount;
+};
+
+typedef struct Gphoto2Device Gphoto2Device;
+
+GHashTable *devices;
+GMutex *devices_mutex;
+
 struct _GVfsBackendGphoto2
 {
   GVfsBackend parent_instance;
 
   /* a gphoto2 specific identifier for the gphoto2 camera such as usb:001,041 */
   char *gphoto2_port;
+  char *store_path;
+  char *store_desc;
   GPContext *context;
   Camera *camera;
 
-  /* see comment in ensure_ignore_prefix() */
+  /* see comment in set_ignore_prefix() */
   char *ignore_prefix;
 
   /* list of open files */
@@ -333,7 +340,17 @@
 }
 
 /* ------------------------------------------------------------------------------------------------- */
+static void
+destroy_device (gpointer data)
+{
+  Gphoto2Device *device = (Gphoto2Device *) data;
+  gp_context_unref (device->context);
+  gp_camera_unref (device->camera);
+  g_free (device);
+}
 
+/* ------------------------------------------------------------------------------------------------- */
+
 /* used when gphoto2 will take ownership of this data for it's LRU cache - and will use free(3) to free it */
 static char *
 dup_for_gphoto2 (char *gmem, unsigned long int size)
@@ -531,19 +548,24 @@
 {
   GList *l;
 
-  g_free (gphoto2_backend->gphoto2_port);
-  gphoto2_backend->gphoto2_port = NULL;
 
-  if (gphoto2_backend->context != NULL)
+  if (gphoto2_backend->gphoto2_port)
     {
-      gp_context_unref (gphoto2_backend->context);
-      gphoto2_backend->context = NULL;
-    }
+      Gphoto2Device *device;
 
-  if (gphoto2_backend->camera != NULL)
-    {
-      gp_camera_unref (gphoto2_backend->camera);
-      gphoto2_backend->camera = NULL;
+      g_mutex_lock (devices_mutex);
+
+      device = g_hash_table_lookup (devices, gphoto2_backend->gphoto2_port);
+
+      if (device != NULL)
+        {
+          if (g_atomic_int_dec_and_test (&device->refcount))
+            {
+              g_hash_table_remove (devices, device);
+            }
+        }
+
+      g_mutex_unlock (devices_mutex);
     }
 
   if (gphoto2_backend->dbus_connection != NULL)
@@ -608,6 +630,13 @@
     }
   gphoto2_backend->capacity = -1;
   gphoto2_backend->free_space = -1;
+
+  g_free (gphoto2_backend->gphoto2_port);
+  gphoto2_backend->gphoto2_port = NULL;
+  g_free (gphoto2_backend->store_desc);
+  gphoto2_backend->store_desc = NULL;
+  g_free (gphoto2_backend->store_path);
+  gphoto2_backend->store_path = NULL;
 }
 
 /* ------------------------------------------------------------------------------------------------- */
@@ -698,8 +727,8 @@
 
 /* ------------------------------------------------------------------------------------------------- */
 
-static void
-find_udi_for_device (GVfsBackendGphoto2 *gphoto2_backend)
+static gboolean
+find_udi_for_device (GVfsBackendGphoto2 *gphoto2_backend, const char *host)
 {
   int num_camera_devices;
   int num_mtp_devices;
@@ -719,36 +748,41 @@
 
   /* parse the usb:001,041 string */
 
-  if (!g_str_has_prefix (gphoto2_backend->gphoto2_port, "usb:"))
+  if (!g_str_has_prefix (host, "[usb:"))
     {
-      return;
+      return FALSE;
     }
 
-  tokens = g_strsplit (gphoto2_backend->gphoto2_port + 4, ",", 0);
-  if (g_strv_length (tokens) != 2)
+  tokens = g_strsplit (host + 5, ",", 0);
+  if (g_strv_length (tokens) != 3)
     {
       g_strfreev (tokens);
-      return;
+      return FALSE;
     }
 
   usb_bus_num = strtol (tokens[0], &endp, 10);
   if (*endp != '\0')
     {
       g_strfreev (tokens);
-      return;
+      return FALSE;
     }
 
   usb_device_num = strtol (tokens[1], &endp, 10);
   if (*endp != '\0')
     {
       g_strfreev (tokens);
-      return;
+      return FALSE;
     }
 
+  gphoto2_backend->store_path = g_strdup (tokens[2]);
+  gphoto2_backend->store_path[strlen (gphoto2_backend->store_path) - 1] = '\0';
+
   g_strfreev (tokens);
 
-  DEBUG ("Parsed '%s' into bus=%d device=%d", gphoto2_backend->gphoto2_port, usb_bus_num, usb_device_num);
+  gphoto2_backend->gphoto2_port = g_strdup_printf ("usb:%d,%d", usb_bus_num, usb_device_num);
 
+  DEBUG ("Parsed '%s' into bus=%d device=%d store_path=%s", host, usb_bus_num, usb_device_num, gphoto2_backend->store_path);
+
   camera_devices = libhal_find_device_by_capability (gphoto2_backend->hal_ctx,
                                                      "camera",
                                                      &num_camera_devices,
@@ -891,6 +925,8 @@
           libhal_free_string_array (devices);
         }
     }
+
+  return TRUE;
 }
 
 /* ------------------------------------------------------------------------------------------------- */
@@ -910,7 +946,7 @@
       caches_invalidate_all (gphoto2_backend);
 
       /* TODO: need a cleaner way to force unmount ourselves */
-      exit (1);
+      release_device(gphoto2_backend);
     }
 }
 
@@ -1281,85 +1317,18 @@
 
 /* ------------------------------------------------------------------------------------------------- */
 
-/* The PTP gphoto2 backend puts an annoying virtual store_00010001
+/* The PTP gphoto2 backend uses separate virtual store_00010001
  * directory in the root (in fact 00010001 can be any hexedecimal
  * digit).
  *
- * We want to skip that as the x-content detection expects to find the
- * DCIM/ folder. As such, this function tries to detect the presence
- * of such a folder in the root and, if found, sets a variable that is
- * prepended to any path passed to libgphoto2. This is cached for as
- * long as we got a connection to libgphoto2. If this operation fails
- * then the passed job will be cancelled and this function will return
- * FALSE.
+ * We have one ignore_prefix per handled storage head.
  *
  * This function needs to be called from do_mount().
  */
-static gboolean
-ensure_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, GVfsJob *job)
+static void
+set_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, GVfsJob *job)
 {
-  int rc;
-  char *prefix;
-  GError *error;
-  CameraList *list;
-
-  /* already set */
-  if (gphoto2_backend->ignore_prefix != NULL)
-    return TRUE;
-
-  /* check folders in / - if there is exactly one folder of the form "store_" followed by eight
-   * hexadecimal digits.. then use that as ignore_prefix.. otherwise don't use anything 
-   */
-
-  gp_list_new (&list);
-  rc = gp_camera_folder_list_folders (gphoto2_backend->camera, 
-                                      "/", 
-                                      list, 
-                                      gphoto2_backend->context);
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Failed to get folder list"), rc);
-      g_vfs_job_failed_from_error (job, error);
-      g_error_free (error);
-      return FALSE;
-  }  
-
-  prefix = NULL;
-
-  if (gp_list_count (list) == 1)
-    {
-      char *name;
-      const char *s;
-      unsigned int n;
-
-      gp_list_get_name (list, 0, &s);
-
-      name = g_ascii_strdown (s, -1);
-      if (g_str_has_prefix (name, "store_") && strlen (name) == 14)
-        {
-          for (n = 6; n < 14; n++)
-            {
-              if (!g_ascii_isxdigit (name[n]))
-                {
-                  break;
-                }
-            }
-          if (n == 14)
-            {
-              prefix = g_strconcat ("/", name, "/", NULL);
-            }
-        }
-
-      g_free (name);
-    }
-  gp_list_free (list);
-
-  if (prefix == NULL)
-    gphoto2_backend->ignore_prefix = g_strdup ("/");
-  else
-    gphoto2_backend->ignore_prefix = prefix;
-
-  return TRUE;
+  gphoto2_backend->ignore_prefix = g_strconcat ("/", gphoto2_backend->store_path, "/", NULL);
 }
 
 /* ------------------------------------------------------------------------------------------------- */
@@ -1385,6 +1354,7 @@
   DBusError dbus_error;
   CameraStorageInformation *storage_info;
   int num_storage_info;
+  Gphoto2Device *device;
 
   DEBUG ("do_mount %p", gphoto2_backend);
 
@@ -1443,110 +1413,142 @@
       return;
     }
 
-  gphoto2_backend->gphoto2_port = g_strdup (host + 1);
-  gphoto2_backend->gphoto2_port[strlen (gphoto2_backend->gphoto2_port) - 1] = '\0';
-
-  DEBUG ("  decoded host='%s'", gphoto2_backend->gphoto2_port);
-
-  find_udi_for_device (gphoto2_backend);
-
-  gphoto2_backend->context = gp_context_new ();
-  if (gphoto2_backend->context == NULL)
+  if (find_udi_for_device (gphoto2_backend, host) == FALSE)
     {
-      g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot create gphoto2 context"));
+      g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot parse hostname"));
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
       g_error_free (error);
       release_device (gphoto2_backend);
       return;
     }
 
-  rc = gp_camera_new (&(gphoto2_backend->camera));
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Error creating camera"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
+  DEBUG ("  decoded host='%s'", gphoto2_backend->gphoto2_port);
 
+  /* Look for the device in the connected devices table */
+  g_mutex_lock (devices_mutex);
+  device = g_hash_table_lookup (devices, gphoto2_backend->gphoto2_port);
 
-  il = NULL;
-  
-  rc = gp_port_info_list_new (&il);
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Error loading device information"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
+  g_message ("device %p", device);
 
-  rc = gp_port_info_list_load (il);
-  if (rc != 0)
+  if (device == NULL)
     {
-      error = get_error_from_gphoto2 (_("Error loading device information"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
+      gphoto2_backend->context = gp_context_new ();
+      if (gphoto2_backend->context == NULL)
+        {
+          g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot create gphoto2 context"));
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
 
-  DEBUG ("  gphoto2_port='%s'", gphoto2_backend->gphoto2_port);
+      rc = gp_camera_new (&(gphoto2_backend->camera));
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error creating camera"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
 
-  n = gp_port_info_list_lookup_path (il, gphoto2_backend->gphoto2_port);
-  if (n == GP_ERROR_UNKNOWN_PORT)
-    {
-      error = get_error_from_gphoto2 (_("Error looking up device information"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
 
-  rc = gp_port_info_list_get_info (il, n, &info);
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Error getting device information"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
+      il = NULL;
 
-  DEBUG ("  '%s' '%s' '%s'",  info.name, info.path, info.library_filename);
-  
-  /* set port */
-  rc = gp_camera_set_port_info (gphoto2_backend->camera, info);
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Error setting up camera communications port"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
-    }
-  gp_port_info_list_free(il);
+      rc = gp_port_info_list_new (&il);
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error loading device information"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
 
-  rc = gp_camera_init (gphoto2_backend->camera, gphoto2_backend->context);
-  if (rc != 0)
-    {
-      error = get_error_from_gphoto2 (_("Error initializing camera"), rc);
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      release_device (gphoto2_backend);
-      return;
+      rc = gp_port_info_list_load (il);
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error loading device information"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
+
+      DEBUG ("  gphoto2_port='%s'", gphoto2_backend->gphoto2_port);
+
+      n = gp_port_info_list_lookup_path (il, gphoto2_backend->gphoto2_port);
+      if (n == GP_ERROR_UNKNOWN_PORT)
+        {
+          error = get_error_from_gphoto2 (_("Error looking up device information"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
+
+      rc = gp_port_info_list_get_info (il, n, &info);
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error getting device information"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
+
+      DEBUG ("  '%s' '%s' '%s'",  info.name, info.path, info.library_filename);
+
+      /* set port */
+      rc = gp_camera_set_port_info (gphoto2_backend->camera, info);
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error setting up camera communications port"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
+      gp_port_info_list_free(il);
+
+      rc = gp_camera_init (gphoto2_backend->camera, gphoto2_backend->context);
+      if (rc != 0)
+        {
+          error = get_error_from_gphoto2 (_("Error initializing camera"), rc);
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          g_mutex_unlock (devices_mutex);
+          release_device (gphoto2_backend);
+          return;
+        }
+
+      device = g_new0 (Gphoto2Device, 1);
+      g_atomic_int_inc (&device->refcount);
+      device->camera = gphoto2_backend->camera;
+      device->context = gphoto2_backend->context;
+
+      g_hash_table_insert (devices, gphoto2_backend->gphoto2_port, device);
     }
-
-  if (!ensure_ignore_prefix (gphoto2_backend, G_VFS_JOB (job)))
+  else
     {
-      release_device (gphoto2_backend);
-      return;
+      gphoto2_backend->camera = device->camera;
+      gphoto2_backend->context = device->context;
+      g_atomic_int_inc (&device->refcount);
     }
 
+  g_mutex_unlock (devices_mutex);
+
+  set_ignore_prefix (gphoto2_backend, G_VFS_JOB (job));
+
   /* Translator: %s represents the device, e.g. usb:001,042  */
-  fuse_name = g_strdup_printf (_("gphoto2 mount on %s"), gphoto2_backend->gphoto2_port);
+  fuse_name = g_strdup_printf (_("gphoto2 mount on %s"), gphoto2_backend->gphoto2_port); //FIXME multi mounts!
   icon_name = compute_icon_name (gphoto2_backend);
   display_name = compute_display_name (gphoto2_backend);
   g_vfs_backend_set_stable_name (backend, fuse_name);
@@ -3397,4 +3399,11 @@
   backend_class->try_query_info = try_query_info;
   backend_class->try_enumerate = try_enumerate;
   backend_class->try_query_fs_info = try_query_fs_info;
+
+  devices_mutex = g_mutex_new ();
+  devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_device);
 }
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
