[gvfs] gphoto2: Switch to a stable device uri
- From: Philip Langdale <philipl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] gphoto2: Switch to a stable device uri
- Date: Wed, 18 Apr 2018 23:07:33 +0000 (UTC)
commit efc76d0cd84df8904ea661cb0e04728e3e6205d4
Author: Philip Langdale <philipl overt org>
Date: Tue Apr 17 20:29:05 2018 -0700
gphoto2: Switch to a stable device uri
For the same reasons that the equivalent change to the mtp backend
was desirable, we want to do this in the gphoto2 (ptp) backend.
Stable URIs allow things like bookmarking and external scripting
to work across plug/unplug events (which is to say, allows them
to work at all).
See the change description for the mtp backend for more details.
https://bugzilla.gnome.org/show_bug.cgi?id=795311
daemon/gvfsbackendgphoto2.c | 57 +++++++++++++++++++++++++----
monitor/gphoto2/ggphoto2volumemonitor.c | 60 ++++++++++++++++++++++++++++---
2 files changed, 105 insertions(+), 12 deletions(-)
---
diff --git a/daemon/gvfsbackendgphoto2.c b/daemon/gvfsbackendgphoto2.c
index 240b326..b31bc59 100644
--- a/daemon/gvfsbackendgphoto2.c
+++ b/daemon/gvfsbackendgphoto2.c
@@ -1210,6 +1210,49 @@ ensure_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, GVfsJob *job)
/* ------------------------------------------------------------------------------------------------- */
+static char *
+get_port_from_host (GVfsJob *job,
+ GUdevClient *gudev_client,
+ const char *host)
+{
+ guint32 bus_num = 0, dev_num = 0;
+ GList *devices, *l;
+
+ /* find corresponding GUdevDevice */
+ devices = g_udev_client_query_by_subsystem (gudev_client, "usb");
+ for (l = devices; l != NULL; l = l->next)
+ {
+ const char *id = g_udev_device_get_property (l->data, "ID_SERIAL");
+ if (g_strcmp0 (id, host) == 0)
+ {
+ bus_num = g_ascii_strtoull (g_udev_device_get_property (l->data, "BUSNUM"),
+ NULL, 10);
+ dev_num = g_ascii_strtoull (g_udev_device_get_property (l->data, "DEVNUM"),
+ NULL, 10);
+ break;
+ }
+ }
+ g_list_free_full (devices, g_object_unref);
+
+ if (bus_num && dev_num)
+ {
+ return g_strdup_printf ("usb:%03u,%03u", bus_num, dev_num);
+ }
+
+ /* For compatibility, handle old style host specifications. */
+ if (g_str_has_prefix (host, "[usb:") && host[strlen (host) - 1] == ']')
+ {
+ char *port = g_strdup (host + 1);
+ port[strlen (port) -1] = '\0';
+ return port;
+ }
+
+ g_vfs_job_failed_literal (G_VFS_JOB (job),
+ G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Couldn’t find matching udev device."));
+ return NULL;
+}
+
static void
do_mount (GVfsBackend *backend,
GVfsJobMount *job,
@@ -1251,16 +1294,16 @@ do_mount (GVfsBackend *backend,
host = g_mount_spec_get (mount_spec, "host");
g_debug (" host='%s'\n", host);
- if (host == NULL || strlen (host) < 3 || host[0] != '[' || host[strlen (host) - 1] != ']')
+
+ char *port = get_port_from_host (G_VFS_JOB (job),
+ gphoto2_backend->gudev_client,
+ host);
+ if (port == NULL)
{
- g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("No device specified"));
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
+ /* Job already set to failed */
return;
}
-
- gphoto2_backend->gphoto2_port = g_strdup (host + 1);
- gphoto2_backend->gphoto2_port[strlen (gphoto2_backend->gphoto2_port) - 1] = '\0';
+ gphoto2_backend->gphoto2_port = port;
g_debug (" decoded host='%s'\n", gphoto2_backend->gphoto2_port);
diff --git a/monitor/gphoto2/ggphoto2volumemonitor.c b/monitor/gphoto2/ggphoto2volumemonitor.c
index a9f51de..6bd9fc8 100644
--- a/monitor/gphoto2/ggphoto2volumemonitor.c
+++ b/monitor/gphoto2/ggphoto2volumemonitor.c
@@ -139,7 +139,10 @@ gudev_add_camera (GGPhoto2VolumeMonitor *monitor, GUdevDevice *device, gboolean
GGPhoto2Volume *volume;
GList *store_heads, *l;
guint num_store_heads;
- const char *usb_bus_num, *usb_device_num, *device_path;
+ const char *usb_bus_num, *usb_device_num, *usb_serial_id, *device_path;
+ gchar *prefix;
+ GFile *mount_prefix;
+ gboolean serial_conflict = FALSE;
device_path = g_udev_device_get_device_file (device);
if (!device_path)
@@ -157,6 +160,17 @@ gudev_add_camera (GGPhoto2VolumeMonitor *monitor, GUdevDevice *device, gboolean
}
#endif /* HAVE_LIBMTP */
+ /*
+ * We do not use ID_SERIAL_SHORT (the actualy device serial value) as
+ * this field is not populated when an ID_SERIAL has to be synthesized.
+ */
+ usb_serial_id = g_udev_device_get_property (device, "ID_SERIAL");
+ if (usb_serial_id == NULL)
+ {
+ g_warning ("device %s has no ID_SERIAL property, ignoring", device_path);
+ return;
+ }
+
usb_bus_num = g_udev_device_get_property (device, "BUSNUM");
if (usb_bus_num == NULL)
{
@@ -171,9 +185,45 @@ gudev_add_camera (GGPhoto2VolumeMonitor *monitor, GUdevDevice *device, gboolean
return;
}
- g_debug ("gudev_add_camera: camera device %s (bus: %s, device: %s)",
+ prefix = g_strdup_printf ("gphoto2://%s", usb_serial_id);
+ mount_prefix = g_file_new_for_uri (prefix);
+ g_free (prefix);
+
+ /*
+ * We do not support plugging in multiple devices that lack proper serial
+ * numbers. Linux will attempt to synthesize an ID based on the device
+ * product information, which will avoid collisions between different
+ * types of device, but two identical, serial-less, devices will still
+ * conflict.
+ */
+ for (l = monitor->camera_volumes; l != NULL; l = l->next)
+ {
+ GGPhoto2Volume *volume = G_GPHOTO2_VOLUME (l->data);
+
+ GFile *existing_root = g_volume_get_activation_root (G_VOLUME (volume));
+ if (g_file_equal (existing_root, mount_prefix) ||
+ g_file_has_prefix (existing_root, mount_prefix))
+ {
+ serial_conflict = TRUE;
+ }
+ g_object_unref (existing_root);
+ if (serial_conflict)
+ {
+ break;
+ }
+ }
+ g_object_unref (mount_prefix);
+ if (serial_conflict)
+ {
+ g_warning ("device %s has an identical ID_SERIAL value to an "
+ "existing device. Multiple devices are not supported.",
+ g_udev_device_get_device_file (device));
+ return;
+ }
+
+ g_debug ("gudev_add_camera: camera device %s (id: %s)",
g_udev_device_get_device_file (device),
- usb_bus_num, usb_device_num);
+ usb_serial_id);
store_heads = get_stores_for_camera (usb_bus_num, usb_device_num);
num_store_heads = g_list_length (store_heads);
@@ -189,11 +239,11 @@ gudev_add_camera (GGPhoto2VolumeMonitor *monitor, GUdevDevice *device, gboolean
*/
if (num_store_heads == 1)
{
- uri = g_strdup_printf ("gphoto2://[usb:%s,%s]", usb_bus_num, usb_device_num);
+ uri = g_strdup_printf ("gphoto2://%s", usb_serial_id);
}
else
{
- uri = g_strdup_printf ("gphoto2://[usb:%s,%s]/%s", usb_bus_num, usb_device_num,
+ uri = g_strdup_printf ("gphoto2://%s/%s", usb_serial_id,
store_path[0] == '/' ? store_path + 1 : store_path);
}
g_debug ("gudev_add_camera: ... adding URI for storage head: %s", uri);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]