[gvfs] afp: add GVfsAfpConnection which handles the DSI connection



commit 73e0352e827216575822d54cf1c1eb9f220bf2e1
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date:   Sun May 29 00:38:42 2011 +0200

    afp: add GVfsAfpConnection which handles the DSI connection

 daemon/Makefile.am         |    4 +-
 daemon/gvfsafpconnection.c |  306 ++++++++++++++++++++++++++++++++++++++++++++
 daemon/gvfsafpconnection.h |   61 +++++++++
 daemon/gvfsbackendafp.c    |   35 +++++
 daemon/gvfsbackendafp.h    |    4 +
 5 files changed, 409 insertions(+), 1 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 269a458..9256e74 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -475,7 +475,9 @@ gvfsd_afc_LDADD = \
 gvfsd_afp_SOURCES = \
 	gvfsbackendafp.c gvfsbackendafp.h \
 	daemon-main.c daemon-main.h \
-	daemon-main-generic.c
+	daemon-main-generic.c \
+	gvfsafpconnection.h \
+	gvfsafpconnection.c
 
 gvfsd_afp_CPPFLAGS = \
 	-DBACKEND_HEADER=gvfsbackendafp.h \
diff --git a/daemon/gvfsafpconnection.c b/daemon/gvfsafpconnection.c
new file mode 100644
index 0000000..8aa2ed0
--- /dev/null
+++ b/daemon/gvfsafpconnection.c
@@ -0,0 +1,306 @@
+ /* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) Carl-Anton Ingmarsson 2011 <ca ingmarsson gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
+ */
+
+
+#include "gvfsafpconnection.h"
+
+
+
+G_DEFINE_TYPE (GVfsAfpConnection, g_vfs_afp_connection, G_TYPE_OBJECT);
+
+struct _GVfsAfpConnectionPrivate
+{
+  GIOStream *conn;
+
+  guint16 request_id;
+
+  guint32 kRequestQuanta;
+  guint32 kServerReplayCacheSize;
+};
+
+typedef enum
+{
+  DSI_CLOSE_SESSION = 1,
+  DSI_COMMAND       = 2,
+  DSI_GET_STATUS    = 3,
+  DSI_OPEN_SESSION  = 4,
+  DSI_TICKLE        = 5,
+  DSI_WRITE         = 6
+} DsiCommand;
+
+static guint16
+get_request_id (GVfsAfpConnection *afp_connection)
+{
+  GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+  return priv->request_id++;
+}
+static char *
+read_reply_sync (GVfsAfpConnection *afp_connection,
+                 guint8            *flags,
+                 DsiCommand        *command,
+                 guint16           *request_id,
+                 gsize             *len,
+                 GCancellable      *cancellable,
+                 GError            **error)
+{
+  GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+  typedef struct {
+    guint8 flags;
+    guint8 command;
+    guint16 requestID;
+    union {
+      guint32 errorCode;
+      guint32 writeOffset;
+    };
+    guint32 totalDataLength;
+    guint32 reserved;
+  } DSIHeader;
+  
+  GInputStream *input;
+  DSIHeader dsi_header;
+  gsize read_count;
+  char *data;
+  
+  input = g_io_stream_get_input_stream (priv->conn);
+
+  read_count = sizeof (DSIHeader);
+  while (read_count > 0)
+  {
+    gsize bytes_read;
+    
+    bytes_read = g_input_stream_read (input,
+                                      &dsi_header + (sizeof (DSIHeader) - read_count),
+                                      read_count, cancellable, error);
+    if (bytes_read == -1)
+      return NULL;
+
+    read_count -= bytes_read;
+  }
+  dsi_header.requestID = GUINT16_FROM_BE (dsi_header.requestID);
+  dsi_header.totalDataLength = GUINT32_FROM_BE (dsi_header.totalDataLength);
+  
+  *flags = dsi_header.flags;
+  *command = dsi_header.command;
+  *request_id = dsi_header.requestID;
+
+  data = g_malloc (dsi_header.totalDataLength);
+  read_count = dsi_header.totalDataLength;
+  while (read_count > 0)
+  {
+    gsize bytes_read;
+    
+    bytes_read = g_input_stream_read (input,
+                                      data + (dsi_header.totalDataLength - read_count),
+                                      read_count, cancellable, error);
+    if (bytes_read == -1)
+    {
+      g_free (data);
+      return NULL;
+    }
+
+    read_count -= bytes_read;
+  }
+
+  *len = dsi_header.totalDataLength;  
+  return data;
+}
+
+static gboolean
+send_request_sync (GVfsAfpConnection *afp_connection,
+                   DsiCommand        command,
+                   gsize             len,
+                   char              *data,
+                   GCancellable      *cancellable,
+                   GError            **error)
+{
+  GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+  typedef struct {
+    guint8 flags;
+    guint8 command;
+    guint16 requestID;
+    union {
+      guint32 errorCode;
+      guint32 writeOffset;
+    };
+    guint32 totalDataLength;
+    guint32 reserved;
+  } DSIHeader;
+  
+  GOutputStream *output;
+  DSIHeader dsi_header;
+  gsize write_count;
+  
+  output = g_io_stream_get_output_stream (priv->conn);
+
+  dsi_header.flags = 0x00;
+  dsi_header.command = command;
+  dsi_header.requestID = GUINT16_TO_BE (get_request_id (afp_connection));
+  dsi_header.writeOffset = 0;
+  dsi_header.totalDataLength = 0; 
+  dsi_header.reserved = 0;
+
+  write_count = sizeof (DSIHeader);
+  while (write_count > 0)
+  {
+    gsize bytes_written;
+
+    bytes_written = g_output_stream_write (output,
+                                           &dsi_header + (sizeof (DSIHeader) - write_count),
+                                           write_count, cancellable, error);
+    if (bytes_written == -1)
+      return FALSE;
+
+    write_count -= bytes_written;
+  }
+
+  write_count = len;
+  while (write_count > 0)
+  {
+    gsize bytes_written;
+
+    bytes_written = g_output_stream_write (output, data + (len - write_count),
+                                           write_count, cancellable, error);
+    if (bytes_written == -1)
+      return FALSE;
+
+    write_count -= bytes_written;
+  }
+
+  return TRUE;
+}
+
+GVfsAfpConnection *
+g_vfs_afp_connection_new (GSocketConnectable *addr,
+                          GCancellable       *cancellable,
+                          GError             **error)
+{
+  GVfsAfpConnection *afp_connection;
+  GVfsAfpConnectionPrivate *priv;
+
+  GSocketClient *client;
+
+  char *reply;
+  guint8 flags;
+  DsiCommand command;
+  guint16 request_id;
+  gsize len;
+  guint pos;
+    
+  afp_connection = g_object_new (G_VFS_TYPE_AFP_CONNECTION, NULL);
+  priv = afp_connection->priv;
+  
+  client = g_socket_client_new ();
+  priv->conn = G_IO_STREAM (g_socket_client_connect (client, addr, cancellable, error));
+  g_object_unref (client);
+
+  if (!priv->conn)
+    goto error;
+
+  if (!send_request_sync (afp_connection, DSI_OPEN_SESSION, 0, NULL,
+                          cancellable, error))
+    goto error;
+
+  reply = read_reply_sync (afp_connection, &flags, &command, &request_id, &len,
+                           cancellable, error);
+  if (!reply)
+    goto error;
+
+  pos = 0;
+  while ((len - pos) > 2)
+  {
+    guint8 optionType;
+    guint8 optionLength;
+
+    optionType = reply[pos++];
+    optionLength = reply[pos++];
+
+    switch (optionType)
+    {
+      
+      case 0x00:
+        if (optionLength == 4 && (len - pos) >= 4)
+          priv->kRequestQuanta = GUINT32_FROM_BE (*(guint32 *)(reply + pos));
+
+        break;
+        
+      case 0x02:
+        if (optionLength == 4 && (len - pos) >= 4)
+         priv->kServerReplayCacheSize = GUINT32_FROM_BE (*(guint32 *)(reply + pos));
+
+        break;
+      
+
+      default:
+        g_debug ("Unknown DSI option\n");
+    }
+
+    pos += optionLength;
+  }
+  
+  return afp_connection;
+  
+error:
+  g_object_unref (afp_connection);
+  return NULL;   
+}
+
+static void
+g_vfs_afp_connection_init (GVfsAfpConnection *afp_connection)
+{
+  GVfsAfpConnectionPrivate *priv;
+  
+  afp_connection->priv = priv =  G_TYPE_INSTANCE_GET_PRIVATE (afp_connection,
+                                                              G_VFS_TYPE_AFP_CONNECTION,
+                                                              GVfsAfpConnectionPrivate);
+
+  priv->conn = NULL;
+  priv->request_id = 0;
+
+  priv->kRequestQuanta = -1;
+  priv->kServerReplayCacheSize = -1;
+}
+
+static void
+g_vfs_afp_connection_finalize (GObject *object)
+{
+  GVfsAfpConnection *afp_connection = (GVfsAfpConnection *)object;
+  GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+  if (priv->conn)
+    g_object_unref (priv->conn);
+
+	G_OBJECT_CLASS (g_vfs_afp_connection_parent_class)->finalize (object);
+}
+
+static void
+g_vfs_afp_connection_class_init (GVfsAfpConnectionClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GVfsAfpConnectionPrivate));
+  
+	object_class->finalize = g_vfs_afp_connection_finalize;
+}
+
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
new file mode 100644
index 0000000..86df653
--- /dev/null
+++ b/daemon/gvfsafpconnection.h
@@ -0,0 +1,61 @@
+ /* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) Carl-Anton Ingmarsson 2011 <ca ingmarsson gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
+ */
+
+#ifndef _GVFSAFPCONNECTION_H_
+#define _GVFSAFPCONNECTION_H_
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_AFP_CONNECTION             (g_vfs_afp_connection_get_type ())
+#define G_VFS_AFP_CONNECTION(obj)             (G_VFS_TYPE_CHECK_INSTANCE_CAST ((obj), G_VFS_TYPE_VFS_AFP_CONNECTION, GVfsAfpConnection))
+#define G_VFS_AFP_CONNECTION_CLASS(klass)     (G_VFS_TYPE_CHECK_CLASS_CAST ((klass), G_VFS_TYPE_VFS_AFP_CONNECTION, GVfsAfpConnectionClass))
+#define G_IS_VFS_AFP_CONNECTION(obj)          (G_VFS_TYPE_CHECK_INSTANCE_TYPE ((obj), G_VFS_TYPE_VFS_AFP_CONNECTION))
+#define G_IS_VFS_AFP_CONNECTION_CLASS(klass)  (G_VFS_TYPE_CHECK_CLASS_TYPE ((klass), G_VFS_TYPE_VFS_AFP_CONNECTION))
+#define G_VFS_AFP_CONNECTION_GET_CLASS(obj)   (G_VFS_TYPE_INSTANCE_GET_CLASS ((obj), G_VFS_TYPE_VFS_AFP_CONNECTION, GVfsAfpConnectionClass))
+
+typedef struct _GVfsAfpConnectionClass GVfsAfpConnectionClass;
+typedef struct _GVfsAfpConnection GVfsAfpConnection;
+typedef struct _GVfsAfpConnectionPrivate GVfsAfpConnectionPrivate;
+
+struct _GVfsAfpConnectionClass
+{
+	GObjectClass parent_class;
+};
+
+struct _GVfsAfpConnection
+{
+	GObject parent_instance;
+
+  GVfsAfpConnectionPrivate *priv;
+};
+
+GType g_vfs_afp_connection_get_type (void) G_GNUC_CONST;
+
+GVfsAfpConnection *
+g_vfs_afp_connection_new (GSocketConnectable *addr,
+                          GCancellable       *cancellable,
+                          GError             **error);
+G_END_DECLS
+
+#endif /* _GVFSAFPCONNECTION_H_ */
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index 154c41e..c893a5f 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -35,6 +35,39 @@
 
 G_DEFINE_TYPE (GVfsBackendAfp, g_vfs_backend_afp, G_VFS_TYPE_BACKEND);
 
+static void
+do_unmount (GVfsBackend *   backend,
+            GVfsJobUnmount *job,
+            GMountUnmountFlags flags,
+            GMountSource *mount_source)
+{
+  GVfsBackendAfp *afp = G_VFS_BACKEND_AFP (backend);
+
+  g_object_unref (afp->conn);
+}
+
+static void
+do_mount (GVfsBackend *backend,
+          GVfsJobMount *job,
+          GMountSpec *mount_spec,
+          GMountSource *mount_source,
+          gboolean is_automount)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+  GError *err;
+
+  err = NULL;
+  afp_backend->conn = g_vfs_afp_connection_new (afp_backend->addr,
+                                                G_VFS_JOB (job)->cancellable,
+                                                &err);
+  if (!afp_backend->conn)
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
+
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  
+}
+  
 static gboolean
 try_mount (GVfsBackend *backend,
            GVfsJobMount *job,
@@ -93,5 +126,7 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
 	object_class->finalize = g_vfs_backend_afp_finalize;
 
 	backend_class->try_mount = try_mount;
+  backend_class->mount = do_mount;
+  backend_class->unmount = do_unmount;
 }
 
diff --git a/daemon/gvfsbackendafp.h b/daemon/gvfsbackendafp.h
index 230c7f6..ac9cd12 100644
--- a/daemon/gvfsbackendafp.h
+++ b/daemon/gvfsbackendafp.h
@@ -25,6 +25,8 @@
 
 #include <gvfsbackend.h>
 
+#include "gvfsafpconnection.h"
+
 G_BEGIN_DECLS
 
 #define G_VFS_TYPE_BACKEND_AFP             (g_vfs_backend_afp_get_type ())
@@ -48,6 +50,8 @@ struct _GVfsBackendAfp
 
 	GSocketConnectable *addr;
 	char               *user;
+
+  GVfsAfpConnection  *conn;
 };
 
 GType g_vfs_backend_afp_get_type (void) G_GNUC_CONST;



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