[gvfs] afp: add read support



commit 4d02b2aee2a4d26a7a42d56c69c3ea0d0c0345ec
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date:   Thu Jun 23 20:21:35 2011 +0200

    afp: add read support

 daemon/gvfsafpconnection.c |   16 ++-
 daemon/gvfsafpconnection.h |   36 ++++--
 daemon/gvfsbackendafp.c    |  307 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 337 insertions(+), 22 deletions(-)
---
diff --git a/daemon/gvfsafpconnection.c b/daemon/gvfsafpconnection.c
index d70ec07..7865363 100644
--- a/daemon/gvfsafpconnection.c
+++ b/daemon/gvfsafpconnection.c
@@ -87,9 +87,9 @@ struct _GVfsAfpReply
   AfpResultCode result_code;
 
   char *data;
-  guint len;
+  gsize len;
 
-  gint pos;
+  goffset pos;
 };
 
 G_DEFINE_TYPE (GVfsAfpReply, g_vfs_afp_reply, G_TYPE_OBJECT);
@@ -220,7 +220,7 @@ g_vfs_afp_reply_read_uint16 (GVfsAfpReply *reply, guint16 *val)
 }
 
 gboolean
-g_vfs_afp_reply_get_data (GVfsAfpReply *reply, guint size, guint8 **data)
+g_vfs_afp_reply_get_data (GVfsAfpReply *reply, gsize size, guint8 **data)
 {
   if ((reply->len - reply->pos) < size)
     return FALSE;
@@ -234,7 +234,7 @@ g_vfs_afp_reply_get_data (GVfsAfpReply *reply, guint size, guint8 **data)
 }
 
 gboolean
-g_vfs_afp_reply_dup_data (GVfsAfpReply *reply, guint size, guint8 **data)
+g_vfs_afp_reply_dup_data (GVfsAfpReply *reply, gsize size, guint8 **data)
 {
   if ((reply->len - reply->pos) < size)
     return FALSE;
@@ -355,12 +355,18 @@ g_vfs_afp_reply_skip_to_even (GVfsAfpReply *reply)
   return TRUE;
 }
 
-gint
+goffset
 g_vfs_afp_reply_get_pos (GVfsAfpReply *reply)
 {
   return reply->pos;
 }
 
+gsize
+g_vfs_afp_reply_get_size (GVfsAfpReply *reply)
+{
+  return reply->len;
+}
+
 AfpResultCode
 g_vfs_afp_reply_get_result_code (GVfsAfpReply *reply)
 {
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
index e8b494a..197da4a 100644
--- a/daemon/gvfsafpconnection.h
+++ b/daemon/gvfsafpconnection.h
@@ -36,6 +36,14 @@ typedef enum
 
 enum
 {
+  AFP_ACCESS_MODE_READ_BIT       = (1 << 0),
+  AFP_ACCESS_MODE_WRITE_BIT      = (1 << 1),
+  AFP_ACCESS_MODE_DENY_READ_BIT  = (1 << 4),
+  AFP_ACCESS_MODE_DENY_WRITE_BIT = (1 << 5)
+};
+
+enum
+{
   AFP_FILEDIR_ATTRIBUTES_BITMAP_INVISIBLE_BIT      = 0x1,
   AFP_FILEDIR_ATTRIBUTES_BITMAP_SYSTEM_BIT         = 0x4,
   AFP_FILEDIR_ATTRIBUTES_BITMAP_WRITE_INHIBIT_BIT  = 0x20,
@@ -119,14 +127,17 @@ enum
 
 typedef enum
 {
+  AFP_COMMAND_CLOSE_FORK         = 4,
   AFP_COMMAND_GET_SRVR_INFO      = 15,
   AFP_COMMAND_GET_SRVR_PARMS     = 16,
   AFP_COMMAND_GET_VOL_PARMS      = 17,
   AFP_COMMAND_LOGIN              = 18,
   AFP_COMMAND_LOGIN_CONT         = 19,
   AFP_COMMAND_OPEN_VOL           = 24,
+  AFP_COMMAND_OPEN_FORK          = 26,
   AFP_COMMAND_WRITE              = 33,
   AFP_COMMAND_GET_FILE_DIR_PARMS = 34,
+  AFP_COMMAND_READ_EXT           = 60,
   AFP_COMMAND_WRITE_EXT          = 61,
   AFP_COMMAND_ENUMERATE_EXT      = 66,
   AFP_COMMAND_ENUMERATE_EXT2     = 68
@@ -134,13 +145,17 @@ typedef enum
 
 typedef enum
 {
-  AFP_RESULT_NO_ERROR         = 0,
-  AFP_RESULT_NO_MORE_SESSIONS = -1068,
-  AFP_RESULT_ACCESS_DENIED    = -5000, 
-  AFP_RESULT_AUTH_CONTINUE    = -5001,
-  AFP_RESULT_OBJECT_NOT_FOUND = -5018,
-  AFP_RESULT_PARAM_ERR        = -5019,
-  AFP_RESULT_USER_NOT_AUTH    = -5023
+  AFP_RESULT_NO_ERROR            = 0,
+  AFP_RESULT_NO_MORE_SESSIONS    = -1068,
+  AFP_RESULT_ACCESS_DENIED       = -5000, 
+  AFP_RESULT_AUTH_CONTINUE       = -5001,
+  AFP_RESULT_EOF_ERR             = -5009,
+  AFP_RESULT_LOCK_ERR            = -5013,
+  AFP_RESULT_OBJECT_NOT_FOUND    = -5018,
+  AFP_RESULT_PARAM_ERR           = -5019,
+  AFP_RESULT_USER_NOT_AUTH       = -5023,
+  AFP_RESULT_OBJECT_TYPE_ERR     = -5025,
+  AFP_RESULT_TOO_MANY_FILES_OPEN = -5026
 } AfpResultCode;
 
 /*
@@ -187,8 +202,8 @@ gboolean        g_vfs_afp_reply_read_uint64       (GVfsAfpReply *reply, guint64
 gboolean        g_vfs_afp_reply_read_uint32       (GVfsAfpReply *reply, guint32 *val);
 gboolean        g_vfs_afp_reply_read_uint16       (GVfsAfpReply *reply, guint16 *val);
 
-gboolean        g_vfs_afp_reply_get_data          (GVfsAfpReply *reply, guint size, guint8 **data);
-gboolean        g_vfs_afp_reply_dup_data          (GVfsAfpReply *reply, guint size, guint8 **data);
+gboolean        g_vfs_afp_reply_get_data          (GVfsAfpReply *reply, gsize size, guint8 **data);
+gboolean        g_vfs_afp_reply_dup_data          (GVfsAfpReply *reply, gsize size, guint8 **data);
 
 gboolean        g_vfs_afp_reply_read_pascal       (GVfsAfpReply *reply, char **str);
 gboolean        g_vfs_afp_reply_read_afp_name     (GVfsAfpReply *reply, gboolean read_text_encoding, GVfsAfpName **afp_name);
@@ -197,7 +212,8 @@ gboolean        g_vfs_afp_reply_seek              (GVfsAfpReply *reply, gint off
 gboolean        g_vfs_afp_reply_skip_to_even      (GVfsAfpReply *reply);
 
 AfpResultCode   g_vfs_afp_reply_get_result_code   (GVfsAfpReply *reply);
-gint            g_vfs_afp_reply_get_pos           (GVfsAfpReply *reply);
+goffset         g_vfs_afp_reply_get_pos           (GVfsAfpReply *reply);
+gsize           g_vfs_afp_reply_get_size          (GVfsAfpReply *reply);
 
 GType           g_vfs_afp_reply_get_type         (void) G_GNUC_CONST;
 
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index d961635..6f544b3 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -34,6 +34,9 @@
 #include "gvfsjobmount.h"
 #include "gvfsjobenumerate.h"
 #include "gvfsjobqueryinfo.h"
+#include "gvfsjobopenforread.h"
+#include "gvfsjobcloseread.h"
+#include "gvfsjobread.h"
 
 #include "gvfsafpserver.h"
 #include "gvfsafpconnection.h"
@@ -104,6 +107,293 @@ filename_to_afp_pathname (const char *filename)
   return g_vfs_afp_name_new (0x08000103, str, len);
 }
 
+typedef struct
+{
+  gint16 fork_refnum;
+  gint64 offset;
+} AfpHandle;
+
+static AfpHandle *
+afp_handle_new (gint16 fork_refnum)
+{
+  AfpHandle *afp_handle;
+
+  afp_handle = g_slice_new0 (AfpHandle);
+  afp_handle->fork_refnum = fork_refnum;
+
+  return afp_handle;
+}
+
+static void
+afp_handle_free (AfpHandle *afp_handle)
+{
+  g_slice_free (AfpHandle, afp_handle);
+}
+
+static void
+read_ext_cb (GVfsAfpConnection *afp_connection,
+             GVfsAfpReply      *reply,
+             GError            *error,
+             gpointer           user_data)
+{
+  GVfsJobRead *job = G_VFS_JOB_READ (user_data);
+  AfpHandle *afp_handle = (AfpHandle *)job->handle;
+
+  AfpResultCode res_code;
+  gsize size;
+  char *data;
+
+  if (!reply)
+  {
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+    return;
+  }
+
+  res_code = g_vfs_afp_reply_get_result_code (reply);
+  if (!(res_code == AFP_RESULT_NO_ERROR || res_code == AFP_RESULT_EOF_ERR
+        || res_code == AFP_RESULT_LOCK_ERR))
+  {
+    g_object_unref (reply);
+
+    if (res_code == AFP_RESULT_ACCESS_DENIED)
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+                                _("File is not open for read access"));
+    }
+    else
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+                                _("Got error from server"));
+    }
+    return;
+  }
+
+  size = g_vfs_afp_reply_get_size (reply);
+
+  /* TODO: Read directly into the data buffer */
+  g_vfs_afp_reply_get_data (reply, size, (guint8 **)&data);
+  memcpy (job->buffer, data, size);
+
+  afp_handle->offset += size;
+  g_vfs_job_read_set_size (job, size);
+
+  g_object_unref (reply);
+  
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+}
+
+static gboolean 
+try_read (GVfsBackend *backend,
+          GVfsJobRead *job,
+          GVfsBackendHandle handle,
+          char *buffer,
+          gsize bytes_requested)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+  AfpHandle *afp_handle = (AfpHandle *)handle;
+  
+  GVfsAfpCommand *comm;
+  guint32 req_count;
+
+  comm = g_vfs_afp_command_new (AFP_COMMAND_READ_EXT);
+  /* pad byte */
+  g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+
+  /* OForkRefNum */
+  g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm),
+                                  afp_handle->fork_refnum, NULL, NULL);
+  /* Offset */
+  g_data_output_stream_put_int64 (G_DATA_OUTPUT_STREAM (comm),
+                                  afp_handle->offset, NULL, NULL);
+  /* ReqCount */
+  req_count = MIN (bytes_requested, G_MAXUINT32);
+  g_data_output_stream_put_int64 (G_DATA_OUTPUT_STREAM (comm),
+                                  req_count, NULL, NULL);
+
+  g_vfs_afp_connection_queue_command (afp_backend->server->conn, comm,
+                                      read_ext_cb, G_VFS_JOB (job)->cancellable,
+                                      job);
+  g_object_unref (comm);
+
+  return TRUE;
+}
+
+static void
+close_fork_cb (GVfsAfpConnection *afp_connection,
+               GVfsAfpReply      *reply,
+               GError            *error,
+               gpointer           user_data)
+{
+  GVfsJobCloseRead *job = G_VFS_JOB_CLOSE_READ (user_data);
+  AfpHandle *afp_handle = (AfpHandle *)job->handle;
+
+  AfpResultCode res_code;
+  
+  if (!reply)
+  {
+    afp_handle_free (afp_handle);
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+    return;
+  }
+
+  res_code = g_vfs_afp_reply_get_result_code (reply);
+  g_object_unref (reply);
+
+  if (res_code != AFP_RESULT_NO_ERROR)
+  {
+    g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+                      _("Got error from server"));
+  }
+  else
+    g_vfs_job_succeeded (G_VFS_JOB (job));
+
+  afp_handle_free (afp_handle);
+}
+
+static gboolean
+try_close_read (GVfsBackend *backend,
+                GVfsJobCloseRead *job,
+                GVfsBackendHandle handle)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+  AfpHandle *afp_handle = (AfpHandle *)handle;
+
+  GVfsAfpCommand *comm;
+
+  comm = g_vfs_afp_command_new (AFP_COMMAND_CLOSE_FORK);
+  /* pad byte */
+  g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+
+  g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm), afp_handle->fork_refnum,
+                                  NULL, NULL);
+
+  g_vfs_afp_connection_queue_command (afp_backend->server->conn, comm,
+                                      close_fork_cb, G_VFS_JOB (job)->cancellable,
+                                      job);
+  g_object_unref (comm);
+
+  return TRUE;
+}
+
+static void
+open_for_read_cb (GVfsAfpConnection *afp_connection,
+                  GVfsAfpReply      *reply,
+                  GError            *error,
+                  gpointer           user_data)
+{
+  GVfsJobOpenForRead *job = G_VFS_JOB_OPEN_FOR_READ (user_data);
+
+  AfpResultCode res_code;
+  guint16 file_bitmap;
+  gint16 fork_refnum;
+  AfpHandle *afp_handle;
+  
+  if (!reply)
+  {
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+    return;
+  }
+
+  res_code = g_vfs_afp_reply_get_result_code (reply);
+  if (res_code != AFP_RESULT_NO_ERROR)
+  {
+    g_object_unref (reply);
+    
+    if (res_code == AFP_RESULT_ACCESS_DENIED)
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+                                _("Access denied"));
+    }
+    else if (res_code == AFP_RESULT_OBJECT_NOT_FOUND)
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                                _("File doesn't exist"));
+    }
+    else if (res_code == AFP_RESULT_OBJECT_TYPE_ERR)
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
+                                _("File is a directory"));
+    }
+    else if (res_code == AFP_RESULT_TOO_MANY_FILES_OPEN)
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_TOO_MANY_OPEN_FILES,
+                                _("Too many files open"));
+    }
+    else
+    {
+      g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+                                _("Got error from server"));
+    }
+    return;
+  }
+
+  g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+  g_vfs_afp_reply_read_int16  (reply, &fork_refnum);
+
+  g_object_unref (reply);
+  
+  afp_handle = afp_handle_new (fork_refnum);
+  g_vfs_job_open_for_read_set_handle (job, afp_handle);
+
+  g_vfs_job_open_for_read_set_can_seek (job, TRUE);
+  
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+}
+
+static gboolean
+try_open_for_read (GVfsBackend *backend,
+                   GVfsJobOpenForRead *job,
+                   const char *filename)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+  GVfsAfpCommand *comm;
+  guint16 access_mode;
+  GVfsAfpName *pathname;
+  
+  if (is_root (filename))
+  {
+    g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR,
+                              G_IO_ERROR_NOT_REGULAR_FILE,
+                              _("File is a directory"));
+    return TRUE;
+  }
+
+  comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_FORK);
+  /* data fork */
+  g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+
+  /* Volume ID */
+  g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm),
+                                   afp_backend->volume_id, NULL, NULL);
+  /* Directory ID */
+  g_data_output_stream_put_int32 (G_DATA_OUTPUT_STREAM (comm), 2, NULL, NULL);
+
+  /* Bitmap */
+  g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+  
+  /* AccessMode */
+  access_mode = AFP_ACCESS_MODE_READ_BIT;
+  g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm), access_mode,
+                                   NULL, NULL);
+
+  /* PathType */
+  g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), AFP_PATH_TYPE_UTF8_NAME,
+                                 NULL, NULL);
+
+  pathname = filename_to_afp_pathname (filename);
+  g_vfs_afp_command_put_afp_name (comm, pathname);
+  g_vfs_afp_name_unref (pathname);
+
+  g_vfs_afp_connection_queue_command (afp_backend->server->conn, comm,
+                                      open_for_read_cb,
+                                      G_VFS_JOB (job)->cancellable, job);
+  g_object_unref (comm);
+
+  return TRUE;
+}
+
+
 static guint16
 create_filedir_bitmap (GFileAttributeMatcher *matcher)
 {
@@ -146,7 +436,7 @@ static void fill_info (GVfsBackendAfp *afp_backend,
                        GFileInfo *info, GVfsAfpReply *reply,
                        gboolean directory, guint16 bitmap)
 {
-  gint start_pos;
+  goffset start_pos;
 
   if (directory)
   {
@@ -209,7 +499,7 @@ static void fill_info (GVfsBackendAfp *afp_backend,
   if (bitmap & AFP_FILEDIR_BITMAP_UTF8_NAME_BIT)
   {
     guint16 UTF8Name_offset;
-    gint old_pos;
+    goffset old_pos;
     GVfsAfpName *afp_name;
     char *utf8_name;
 
@@ -293,7 +583,7 @@ enumerate_ext2_cb (GVfsAfpConnection *afp_connection,
   g_vfs_afp_reply_read_int16 (reply, &count);
   for (i = 0; i < count; i++)
   {
-    gint start_pos;
+    goffset start_pos;
     guint16 struct_length;
     guint8 FileDir;
     
@@ -339,7 +629,7 @@ enumerate_ext2 (GVfsJobEnumerate *job,
   
   GVfsAfpCommand *comm;
   guint16 file_bitmap, dir_bitmap;
-  GVfsAfpName *Pathname;
+  GVfsAfpName *pathname;
 
   comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT2);
   /* pad byte */
@@ -376,9 +666,9 @@ enumerate_ext2 (GVfsJobEnumerate *job,
   g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), AFP_PATH_TYPE_UTF8_NAME,
                                  NULL, NULL);
 
-  Pathname = filename_to_afp_pathname (filename);
-  g_vfs_afp_command_put_afp_name (comm, Pathname);
-  g_vfs_afp_name_unref (Pathname);
+  pathname = filename_to_afp_pathname (filename);
+  g_vfs_afp_command_put_afp_name (comm, pathname);
+  g_vfs_afp_name_unref (pathname);
 
   g_vfs_afp_connection_queue_command (conn, comm, enumerate_ext2_cb,
                                       G_VFS_JOB (job)->cancellable, job);
@@ -834,6 +1124,9 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
   backend_class->mount = do_mount;
   backend_class->try_query_info = try_query_info;
   backend_class->try_enumerate = try_enumerate;
+  backend_class->try_open_for_read = try_open_for_read;
+  backend_class->try_close_read = try_close_read;
+  backend_class->try_read = try_read;
 }
 
 void



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