[gvfs] MTP: Refactor read path in preparation for supporting normal files.



commit 4ee8ef9bfeb6b5a4f5d0c21867a0c662fc52f240
Author: Philip Langdale <philipl overt org>
Date:   Sat Feb 23 18:24:05 2013 -0800

    MTP: Refactor read path in preparation for supporting normal files.
    
    The existing logic for reading only works for preview icons, but
    I'm about to add support for reading normal files using special
    MTP calls. For that, we need the read calls to work for both cases.
    
    To achieve that, we need to make reading more stateful.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=695984

 daemon/gvfsbackendmtp.c |  140 +++++++++++++++++++++++++++++++++++++----------
 1 files changed, 110 insertions(+), 30 deletions(-)
---
diff --git a/daemon/gvfsbackendmtp.c b/daemon/gvfsbackendmtp.c
index 8daa2c2..71fb732 100644
--- a/daemon/gvfsbackendmtp.c
+++ b/daemon/gvfsbackendmtp.c
@@ -106,6 +106,26 @@ DEBUG_ENUMERATE (const gchar *message, ...)
 
 
 /************************************************
+ * Private Types
+ ************************************************/
+
+typedef enum {
+  HANDLE_FILE,
+  HANDLE_PREVIEW,
+} HandleType;
+
+typedef struct {
+  HandleType handle_type;
+  uint32_t id;
+  goffset offset;
+  gsize size;
+
+  /* For previews only */
+  GByteArray *bytes;
+} RWHandle;
+
+
+/************************************************
  * Initialization
  ************************************************/
 
@@ -1447,30 +1467,26 @@ do_open_icon_for_read (GVfsBackend *backend,
   guint id = strtol (icon_id, NULL, 10);
 
   if (id > 0) {
+    GByteArray *bytes;
     unsigned char *data;
     unsigned int size;
     int ret = LIBMTP_Get_Thumbnail (G_VFS_BACKEND_MTP (backend)->device, id,
                                     &data, &size);
     if (ret == 0) {
       DEBUG ("File %u has thumbnail: %u", id, size);
-      GByteArray *bytes = g_byte_array_sized_new (size);
+      bytes = g_byte_array_sized_new (size);
       g_byte_array_append (bytes, data, size);
       free (data);
-      g_vfs_job_open_for_read_set_can_seek (G_VFS_JOB_OPEN_FOR_READ (job), FALSE);
-      g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), bytes);
-      g_vfs_job_succeeded (G_VFS_JOB (job));
     } else {
       LIBMTP_filesampledata_t *sample_data = LIBMTP_new_filesampledata_t ();
       ret = LIBMTP_Get_Representative_Sample (G_VFS_BACKEND_MTP (backend)->device,
                                               id, sample_data);
       if (ret == 0) {
         DEBUG ("File %u has sampledata: %u", id, size);
-        GByteArray *bytes = g_byte_array_sized_new (sample_data->size);
+        bytes = g_byte_array_sized_new (sample_data->size);
         g_byte_array_append (bytes, (const guint8 *)sample_data->data, sample_data->size);
+        size = sample_data->size;
         LIBMTP_destroy_filesampledata_t (sample_data);
-        g_vfs_job_open_for_read_set_can_seek (G_VFS_JOB_OPEN_FOR_READ (job), FALSE);
-        g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), bytes);
-        g_vfs_job_succeeded (G_VFS_JOB (job));
       } else {
         DEBUG ("File %u has no thumbnail:", id);
         g_vfs_job_failed (G_VFS_JOB (job),
@@ -1478,58 +1494,121 @@ do_open_icon_for_read (GVfsBackend *backend,
                           G_IO_ERROR_NOT_FOUND,
                           _("No thumbnail for entity '%s'"),
                           icon_id);
+        goto exit;
       }
     }
+
+    RWHandle *handle = g_new0(RWHandle, 1);
+    handle->handle_type = HANDLE_PREVIEW;
+    handle->id = id;
+    handle->offset = 0;
+    handle->size = size;
+    handle->bytes = bytes;
+    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));
   } else {
     g_vfs_job_failed (G_VFS_JOB (job),
                       G_IO_ERROR,
                       G_IO_ERROR_INVALID_ARGUMENT,
                       _("Malformed icon identifier '%s'"),
                       icon_id);
+    goto exit;
   }
+
+ exit:
   g_mutex_unlock (&G_VFS_BACKEND_MTP (backend)->mutex);
 
   DEBUG ("(I) do_open_icon_for_read done.");
 }
+#endif /* HAVE_LIBMTP_GET_THUMBNAIL */
 
 
-static gboolean
-try_read (GVfsBackend *backend,
-          GVfsJobRead *job,
-          GVfsBackendHandle handle,
-          char *buffer,
-          gsize bytes_requested)
+static void
+do_seek_on_read (GVfsBackend *backend,
+                 GVfsJobSeekRead *job,
+                 GVfsBackendHandle opaque_handle,
+                 goffset    offset,
+                 GSeekType  type)
+{
+  RWHandle *handle = opaque_handle;
+  uint32_t id = handle->id;
+  goffset old_offset = handle->offset;
+  gsize size = handle->size;
+
+  DEBUG ("(I) do_seek_on_read (%u %lu %ld %u)", id, old_offset, offset, type);
+  g_mutex_lock (&G_VFS_BACKEND_MTP (backend)->mutex);
+
+  if (type == G_SEEK_END) {
+    offset = size + offset;
+  } else if (type == G_SEEK_CUR) {
+    offset += old_offset;
+  }
+
+  if (offset > size || offset < 0) {
+    g_vfs_job_failed_literal (G_VFS_JOB (job),
+                              G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+                              _("Can't seek outside file"));
+    goto exit;
+  }
+
+  handle->offset = offset;
+  g_vfs_job_seek_read_set_offset (job, offset);
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ exit:
+  g_mutex_unlock (&G_VFS_BACKEND_MTP (backend)->mutex);
+  DEBUG ("(I) do_seek_on_read done. (%lu)", offset);
+}
+
+
+static void
+do_read (GVfsBackend *backend,
+         GVfsJobRead *job,
+         GVfsBackendHandle opaque_handle,
+         char *buffer,
+         gsize bytes_requested)
 {
-  GByteArray *bytes = handle;
+  RWHandle *handle = opaque_handle;
+  uint32_t id = handle->id;
+  goffset offset = handle->offset;
+  gsize size = handle->size;
 
-  DEBUG ("(I) try_read (%u %lu)", bytes->len, bytes_requested);
+  DEBUG ("(I) do_read (%u %lu %lu)", id, offset, bytes_requested);
+  g_mutex_lock (&G_VFS_BACKEND_MTP (backend)->mutex);
 
-  gsize bytes_to_copy =  MIN (bytes->len, bytes_requested);
-  if (bytes_to_copy == 0) {
-    goto out;
+  uint32_t actual;
+  if (handle->handle_type == HANDLE_FILE) {
+    g_assert_not_reached();
+  } else {
+    GByteArray *bytes = handle->bytes;
+    actual = MIN (bytes->len - offset, bytes_requested);
+    memcpy (buffer, bytes->data + offset, actual);
   }
-  memcpy (buffer, bytes->data, bytes_to_copy);
-  g_byte_array_remove_range (bytes, 0, bytes_to_copy);
 
- out:
-  g_vfs_job_read_set_size (job, bytes_to_copy);
+  handle->offset = offset + actual;
+  g_vfs_job_read_set_size (job, actual);
   g_vfs_job_succeeded (G_VFS_JOB (job));
 
-  DEBUG ("(I) try_read done.");
-  return TRUE;
+ exit:
+  g_mutex_unlock (&G_VFS_BACKEND_MTP (backend)->mutex);
+  DEBUG ("(I) do_read done.");
 }
 
 static void
 do_close_read (GVfsBackend *backend,
                 GVfsJobCloseRead *job,
-                GVfsBackendHandle handle)
+                GVfsBackendHandle opaque_handle)
 {
   DEBUG ("(I) do_close_read");
-  g_byte_array_unref (handle);
+  RWHandle *handle = opaque_handle;
+  if (handle->bytes) {
+    g_byte_array_unref (handle->bytes);
+  }
+  g_free(handle);
   g_vfs_job_succeeded (G_VFS_JOB (job));
   DEBUG ("(I) do_close_read done.");
 }
-#endif /* HAVE_LIBMTP_GET_THUMBNAIL */
 
 
 /************************************************
@@ -1560,7 +1639,8 @@ g_vfs_backend_mtp_class_init (GVfsBackendMtpClass *klass)
   backend_class->create_file_monitor = do_create_file_monitor;
 #if HAVE_LIBMTP_1_1_5
   backend_class->open_icon_for_read = do_open_icon_for_read;
-  backend_class->try_read = try_read;
-  backend_class->close_read = do_close_read;
 #endif
+  backend_class->seek_on_read = do_seek_on_read;
+  backend_class->read = do_read;
+  backend_class->close_read = do_close_read;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]