Blob Blame History Raw
From 1dcd334d633a79bf2a81f8bcb8e463864a858fa1 Mon Sep 17 00:00:00 2001
From: Philip Langdale <philipl@overt.org>
Date: Mon, 11 Feb 2013 07:55:11 -0800
Subject: [PATCH 2/5] WIP: Use android extensions to support in place read of
 files.

Allows for opening files directly on the device and reading from them.
---
 configure.ac            |    5 +++
 daemon/gvfsbackendmtp.c |   84 +++++++++++++++++++++++++++++++++++++++++++++--
 daemon/gvfsbackendmtp.h |    2 ++
 3 files changed, 89 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0f5ab9a..4b88316 100644
--- a/configure.ac
+++ b/configure.ac
@@ -548,6 +548,11 @@ if test "x$enable_libmtp" != "xno" -a "x$msg_gudev" = "xyes"; then
         AC_DEFINE(HAVE_LIBMTP_1_1_5, 1, [Define to 1 if libmtp 1.1.5 is available]),
         []
     )
+
+    PKG_CHECK_MODULES(LIBMTP_1_1_6, libmtp >= 1.1.6,
+        AC_DEFINE(HAVE_LIBMTP_1_1_6, 1, [Define to 1 if libmtp 1.1.6 is available]),
+        []
+    )
   fi
 fi
 
diff --git a/daemon/gvfsbackendmtp.c b/daemon/gvfsbackendmtp.c
index 71fb732..9b58f2b 100644
--- a/daemon/gvfsbackendmtp.c
+++ b/daemon/gvfsbackendmtp.c
@@ -631,6 +631,15 @@ get_device (GVfsBackend *backend, const char *id, GVfsJob *job) {
     }
   }
 
+  /* Check supported methods/extensions. */
+  LIBMTP_device_extension_t *extension;
+  for (extension = device->extensions; extension != NULL; extension = extension->next) {
+    if (g_strcmp0 ("android.com", extension->name) == 0) {
+      G_VFS_BACKEND_MTP (backend)->android_extension = TRUE;
+      break;
+    }
+  }
+
  exit:
   DEBUG ("(II) get_device done.");
   return device;
@@ -1455,6 +1464,64 @@ do_set_display_name (GVfsBackend *backend,
 }
 
 
+#if HAVE_LIBMTP_1_1_6
+static void
+do_open_for_read (GVfsBackend *backend,
+                  GVfsJobOpenForRead *job,
+                  const char *filename)
+{
+  if (!G_VFS_BACKEND_MTP (backend)->android_extension) {
+    g_vfs_job_failed_literal (G_VFS_JOB (job),
+                              G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                              _("Operation not supported."));
+    return;
+  }
+
+  DEBUG ("(I) do_open_for_read (%s)", filename);
+  g_mutex_lock (&G_VFS_BACKEND_MTP (backend)->mutex);
+
+  gchar **elements = g_strsplit_set (filename, "/", -1);
+  unsigned int ne = g_strv_length (elements);
+
+  if (ne < 3) {
+    g_vfs_job_failed_literal (G_VFS_JOB (job),
+                              G_IO_ERROR, G_IO_ERROR_FAILED,
+                              _("Cannot open this entity"));
+    goto exit;
+  }
+
+  unsigned int id = strtol (elements[ne-1], NULL, 10);
+
+  LIBMTP_mtpdevice_t *device;
+  device = G_VFS_BACKEND_MTP (backend)->device;
+
+  LIBMTP_file_t *file = LIBMTP_Get_Filemetadata (device, id);
+  if (file == NULL) {
+    fail_job (G_VFS_JOB (job), device);
+    goto exit;
+  }
+
+  RWHandle *handle = g_new0(RWHandle, 1);
+  handle->handle_type = HANDLE_FILE;
+  handle->id = id;
+  handle->offset = 0;
+  handle->size = file->filesize;
+
+  LIBMTP_destroy_file_t (file);
+
+  g_vfs_job_open_for_read_set_can_seek (G_VFS_JOB_OPEN_FOR_READ (job), TRUE);
+  g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), handle);
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ exit:
+  g_strfreev (elements);
+  g_mutex_unlock (&G_VFS_BACKEND_MTP (backend)->mutex);
+
+  DEBUG ("(I) do_open_for_read done.");
+}
+#endif /* HAVE_LIBMTP_1_1_6 */
+
+
 #if HAVE_LIBMTP_1_1_5
 static void
 do_open_icon_for_read (GVfsBackend *backend,
@@ -1521,7 +1588,7 @@ do_open_icon_for_read (GVfsBackend *backend,
 
   DEBUG ("(I) do_open_icon_for_read done.");
 }
-#endif /* HAVE_LIBMTP_GET_THUMBNAIL */
+#endif /* HAVE_LIBMTP_1_1_5 */
 
 
 static void
@@ -1579,7 +1646,17 @@ do_read (GVfsBackend *backend,
 
   uint32_t actual;
   if (handle->handle_type == HANDLE_FILE) {
-    g_assert_not_reached();
+    unsigned char *temp;
+    int ret = LIBMTP_GetPartialObject (G_VFS_BACKEND_MTP (backend)->device, id, offset,
+                                       bytes_requested, &temp, &actual);
+    if (ret != 0) {
+      fail_job (G_VFS_JOB (job), G_VFS_BACKEND_MTP (backend)->device);
+      DEBUG ("(I) job failed.");
+      goto exit;
+    }
+
+    memcpy (buffer, temp, actual);
+    free (temp);
   } else {
     GByteArray *bytes = handle->bytes;
     actual = MIN (bytes->len - offset, bytes_requested);
@@ -1637,6 +1714,9 @@ g_vfs_backend_mtp_class_init (GVfsBackendMtpClass *klass)
   backend_class->set_display_name = do_set_display_name;
   backend_class->create_dir_monitor = do_create_dir_monitor;
   backend_class->create_file_monitor = do_create_file_monitor;
+#if HAVE_LIBMTP_1_1_6
+  backend_class->open_for_read = do_open_for_read;
+#endif
 #if HAVE_LIBMTP_1_1_5
   backend_class->open_icon_for_read = do_open_icon_for_read;
 #endif
diff --git a/daemon/gvfsbackendmtp.h b/daemon/gvfsbackendmtp.h
index 4137b65..0fe1dec 100644
--- a/daemon/gvfsbackendmtp.h
+++ b/daemon/gvfsbackendmtp.h
@@ -57,6 +57,8 @@ struct _GVfsBackendMtp
   GHashTable *monitors;
   guint hb_id;
   gint unmount_started;
+
+  gboolean android_extension;
 };
 
 struct _GVfsBackendMtpClass
-- 
1.7.10.4