[gvfs] afp: try to enumerate volumes
- From: Christian Kellner <gicmo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] afp: try to enumerate volumes
- Date: Thu, 25 Aug 2011 19:21:11 +0000 (UTC)
commit e8025856327d583ad14799549a1a7b06c3070929
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date: Fri Jun 3 01:56:16 2011 +0200
afp: try to enumerate volumes
daemon/gvfsafpconnection.c | 592 ++++++++++++++++++++++++++++++++++++--------
daemon/gvfsafpconnection.h | 45 +++-
daemon/gvfsbackendafp.c | 418 +++++++++++++++++++++++++-------
daemon/gvfsbackendafp.h | 16 ++
4 files changed, 875 insertions(+), 196 deletions(-)
---
diff --git a/daemon/gvfsafpconnection.c b/daemon/gvfsafpconnection.c
index be30b9a..db77eaf 100644
--- a/daemon/gvfsafpconnection.c
+++ b/daemon/gvfsafpconnection.c
@@ -58,9 +58,14 @@ g_vfs_afp_reply_new (AfpErrorCode error_code, const char *data, gsize len)
{
GVfsAfpReply *reply;
- reply = g_object_new (G_VFS_TYPE_AFP_REPLY,
- "base-stream", g_memory_input_stream_new_from_data (data, len, g_free),
- NULL);
+ if (data)
+ reply = g_object_new (G_VFS_TYPE_AFP_REPLY, "base-stream",
+ g_memory_input_stream_new_from_data (data, len, g_free),
+ NULL);
+ else
+ reply = g_object_new (G_VFS_TYPE_AFP_REPLY, "base-stream",
+ g_memory_input_stream_new (), NULL);
+
reply->error_code = error_code;
@@ -152,19 +157,17 @@ g_vfs_afp_command_new (AfpCommandType type)
GVfsAfpCommand *command;
command = g_object_new (G_VFS_TYPE_AFP_COMMAND,
- "base-stream", g_memory_output_stream_new (NULL, 0, g_realloc, g_free));
+ "base-stream", g_memory_output_stream_new (NULL, 0, g_realloc, g_free),
+ NULL);
command->type = type;
g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (command), type, NULL, NULL);
- /* pad byte */
- g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (command), 0, NULL, NULL);
-
return command;
}
void
-g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, char *str)
+g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, const char *str)
{
size_t len;
@@ -175,21 +178,75 @@ g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, char *str)
g_output_stream_write (G_OUTPUT_STREAM (command), str, len, NULL, NULL);
}
+void
+g_vfs_afp_command_pad_to_even (GVfsAfpCommand *command)
+{
+ if (g_vfs_afp_command_get_size (command) % 2 == 1)
+ g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (command), 0, NULL, NULL);
+}
+
+gsize
+g_vfs_afp_command_get_size (GVfsAfpCommand *command)
+{
+ GMemoryOutputStream *mem_stream;
+ mem_stream =
+ G_MEMORY_OUTPUT_STREAM (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (command)));
+
+ return g_memory_output_stream_get_data_size (mem_stream);
+}
+
+char *
+g_vfs_afp_command_get_data (GVfsAfpCommand *command)
+{
+ GMemoryOutputStream *mem_stream;
+
+ mem_stream =
+ G_MEMORY_OUTPUT_STREAM (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (command)));
+
+ return g_memory_output_stream_get_data (mem_stream);
+}
/*
* GVfsAfpConnection
*/
G_DEFINE_TYPE (GVfsAfpConnection, g_vfs_afp_connection, G_TYPE_OBJECT);
+typedef struct {
+ guint8 flags;
+ guint8 command;
+ guint16 requestID;
+ union {
+ guint32 errorCode;
+ guint32 writeOffset;
+ };
+ guint32 totalDataLength;
+ guint32 reserved;
+} DSIHeader;
+
struct _GVfsAfpConnectionPrivate
{
+ GSocketConnectable *addr;
GIOStream *conn;
guint16 request_id;
guint32 kRequestQuanta;
guint32 kServerReplayCacheSize;
+
+ GQueue *request_queue;
+ GHashTable *request_hash;
+
+ /* send loop */
+ gboolean send_loop_running;
+ gsize bytes_written;
+ DSIHeader write_dsi_header;
+
+ /* read loop */
+ gboolean read_loop_running;
+ gsize bytes_read;
+ DSIHeader read_dsi_header;
+ char *data;
};
typedef enum
@@ -202,18 +259,6 @@ typedef enum
DSI_WRITE = 6
} DsiCommand;
-typedef struct {
- guint8 flags;
- guint8 command;
- guint16 requestID;
- union {
- guint32 errorCode;
- guint32 writeOffset;
- };
- guint32 totalDataLength;
- guint32 reserved;
-} DSIHeader;
-
static guint16
get_request_id (GVfsAfpConnection *afp_connection)
{
@@ -222,73 +267,378 @@ get_request_id (GVfsAfpConnection *afp_connection)
return priv->request_id++;
}
-static char *
-read_reply_sync (GVfsAfpConnection *afp_connection,
- DSIHeader *dsi_header,
- GCancellable *cancellable,
- GError **error)
+typedef struct
+{
+ GVfsAfpCommand *command;
+ GVfsAfpConnectionReplyCallback reply_cb;
+ GCancellable *cancellable;
+ gpointer user_data;
+ GVfsAfpConnection *conn;
+} RequestData;
+
+static void
+free_request_data (RequestData *request_data)
+{
+ g_object_unref (request_data->command);
+ g_object_unref (request_data->cancellable);
+
+ g_slice_free (RequestData, request_data);
+}
+
+static void
+dispatch_reply (GVfsAfpConnection *afp_connection)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ RequestData *req_data;
+
+ g_debug ("DISPATCH!!!\n");
+ req_data = g_hash_table_lookup (priv->request_hash,
+ GUINT_TO_POINTER (priv->read_dsi_header.requestID));
+ if (req_data)
+ {
+ GVfsAfpReply *reply;
+
+ reply = g_vfs_afp_reply_new (priv->read_dsi_header.errorCode, priv->data,
+ priv->read_dsi_header.totalDataLength);
+ req_data->reply_cb (afp_connection, reply, NULL, req_data->user_data);
+ g_hash_table_remove (priv->request_hash, GUINT_TO_POINTER (priv->read_dsi_header.requestID));
+ return;
+ }
+
+ g_free (priv->data);
+}
+
+static void read_reply (GVfsAfpConnection *afp_connection);
+
+static void
+read_data_cb (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ GInputStream *input = G_INPUT_STREAM (object);
+ GVfsAfpConnection *afp_connection = G_VFS_AFP_CONNECTION (user_data);
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ gssize bytes_read;
+ GError *err = NULL;
+
+ bytes_read = g_input_stream_read_finish (input, res, &err);
+ if (bytes_read == -1)
+ {
+ g_warning ("FAIL!!! \"%s\"\n", err->message);
+ g_error_free (err);
+ }
+
+ priv->bytes_read += bytes_read;
+ if (priv->bytes_read < priv->read_dsi_header.totalDataLength)
+ {
+ g_input_stream_read_async (input, priv->data + priv->bytes_read,
+ priv->read_dsi_header.totalDataLength - priv->bytes_read,
+ 0, NULL, read_data_cb, afp_connection);
+ return;
+ }
+
+ dispatch_reply (afp_connection);
+ read_reply (afp_connection);
+}
+
+static void
+read_dsi_header_cb (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ GInputStream *input = G_INPUT_STREAM (object);
+ GVfsAfpConnection *afp_connection = G_VFS_AFP_CONNECTION (user_data);
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ gssize bytes_read;
+ GError *err = NULL;
+
+ bytes_read = g_input_stream_read_finish (input, res, &err);
+ if (bytes_read == -1)
+ {
+ g_warning ("FAIL!!! \"%s\"\n", err->message);
+ g_error_free (err);
+ }
+
+ priv->bytes_read += bytes_read;
+ if (priv->bytes_read < sizeof (DSIHeader))
+ {
+ g_input_stream_read_async (input, &priv->read_dsi_header + priv->bytes_read,
+ sizeof (DSIHeader) - priv->bytes_read, 0, NULL,
+ read_dsi_header_cb, afp_connection);
+ return;
+ }
+
+ if (priv->read_dsi_header.totalDataLength > 0)
+ {
+ priv->data = g_malloc (priv->read_dsi_header.totalDataLength);
+ priv->bytes_read = 0;
+ g_input_stream_read_async (input, priv->data, priv->read_dsi_header.totalDataLength,
+ 0, NULL, read_data_cb, afp_connection);
+ return;
+ }
+
+ dispatch_reply (afp_connection);
+ read_reply (afp_connection);
+}
+
+static void
+read_reply (GVfsAfpConnection *afp_connection)
{
GVfsAfpConnectionPrivate *priv = afp_connection->priv;
GInputStream *input;
+
+ input = g_io_stream_get_input_stream (priv->conn);
+
+ priv->bytes_read = 0;
+ priv->data = NULL;
+ g_input_stream_read_async (input, &priv->read_dsi_header, sizeof (DSIHeader), 0, NULL,
+ read_dsi_header_cb, afp_connection);
+}
+
+static void send_request (GVfsAfpConnection *afp_connection);
+
+static void
+write_command_cb (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ GOutputStream *output = G_OUTPUT_STREAM (object);
+ RequestData *request_data = (RequestData *)user_data;
+ GVfsAfpConnectionPrivate *priv = request_data->conn->priv;
+
+ gssize bytes_written;
+ GError *err = NULL;
+
+ char *data;
+ gsize size;
+
+ bytes_written = g_output_stream_write_finish (output, res, &err);
+ if (bytes_written == -1)
+ {
+ request_data->reply_cb (request_data->conn, NULL, err, request_data->user_data);
+ free_request_data (request_data);
+ g_error_free (err);
+ }
+
+ data = g_vfs_afp_command_get_data (request_data->command);
+ size = g_vfs_afp_command_get_size (request_data->command);
+
+ priv->bytes_written += bytes_written;
+ if (priv->bytes_written < size)
+ {
+ g_output_stream_write_async (output, data + priv->bytes_written,
+ size - priv->bytes_written, 0, NULL,
+ write_command_cb, request_data);
+ return;
+ }
+
+ g_hash_table_insert (priv->request_hash,
+ GUINT_TO_POINTER (priv->write_dsi_header.requestID),
+ request_data);
+
+ send_request (request_data->conn);
+}
+
+static void
+write_dsi_header_cb (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ GOutputStream *output = G_OUTPUT_STREAM (object);
+ RequestData *request_data = (RequestData *)user_data;
+ GVfsAfpConnectionPrivate *priv = request_data->conn->priv;
+
+ gssize bytes_written;
+ GError *err = NULL;
+
+ char *data;
+ gsize size;
+
+ bytes_written = g_output_stream_write_finish (output, res, &err);
+ g_debug ("Bytes written:%d\n", bytes_written);
+ if (bytes_written == -1)
+ {
+ request_data->reply_cb (request_data->conn, NULL, err, request_data->user_data);
+ free_request_data (request_data);
+ g_error_free (err);
+ }
+
+ priv->bytes_written += bytes_written;
+ if (priv->bytes_written < sizeof (DSIHeader))
+ {
+ g_output_stream_write_async (output, &priv->write_dsi_header + priv->bytes_written,
+ sizeof (DSIHeader) - priv->bytes_written, 0,
+ NULL, write_dsi_header_cb, request_data);
+ return;
+ }
+
+ data = g_vfs_afp_command_get_data (request_data->command);
+ size = g_vfs_afp_command_get_size (request_data->command);
+
+ priv->bytes_written = 0;
+ g_output_stream_write_async (output, data, size, 0,
+ NULL, write_command_cb, request_data);
+}
+
+static void
+send_request (GVfsAfpConnection *afp_connection)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ RequestData *request_data;
+ guint32 writeOffset;
+ guint8 dsi_command;
+
+ request_data = g_queue_pop_head (priv->request_queue);
+
+ if (!request_data) {
+ priv->send_loop_running = FALSE;
+ return;
+ }
+
+ switch (request_data->command->type)
+ {
+ case AFP_COMMAND_WRITE:
+ writeOffset = 8;
+ dsi_command = DSI_WRITE;
+ break;
+ case AFP_COMMAND_WRITE_EXT:
+ writeOffset = 20;
+ dsi_command = DSI_WRITE;
+ break;
+
+ default:
+ writeOffset = 0;
+ dsi_command = DSI_COMMAND;
+ break;
+ }
+
+ priv->write_dsi_header.flags = 0x00;
+ priv->write_dsi_header.command = dsi_command;
+ priv->write_dsi_header.requestID = get_request_id (afp_connection);
+ priv->write_dsi_header.writeOffset = writeOffset;
+ priv->write_dsi_header.totalDataLength = g_vfs_afp_command_get_size (request_data->command);
+ priv->write_dsi_header.reserved = 0;
+
+ priv->bytes_written = 0;
+ g_output_stream_write_async (g_io_stream_get_output_stream (priv->conn),
+ &priv->write_dsi_header, sizeof (DSIHeader), 0,
+ NULL, write_dsi_header_cb, request_data);
+}
+
+static void
+run_loop (GVfsAfpConnection *afp_connection)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ if (!priv->send_loop_running)
+ {
+ send_request (afp_connection);
+ priv->send_loop_running = TRUE;
+ }
+ if (!priv->read_loop_running)
+ {
+ read_reply (afp_connection);
+ priv->read_loop_running = TRUE;
+ }
+}
+
+void
+g_vfs_afp_connection_queue_command (GVfsAfpConnection *afp_connection,
+ GVfsAfpCommand *command,
+ GVfsAfpConnectionReplyCallback reply_cb,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ RequestData *request_data;
+
+ request_data = g_slice_new (RequestData);
+ request_data->command = g_object_ref (command);
+ request_data->reply_cb = reply_cb;
+ request_data->cancellable = g_object_ref (cancellable);
+ request_data->user_data = user_data;
+ request_data->conn = afp_connection;
+
+ g_queue_push_tail (priv->request_queue, request_data);
+
+ run_loop (afp_connection);
+}
+
+static gboolean
+read_reply_sync (GInputStream *input,
+ DSIHeader *dsi_header,
+ char **data,
+ GCancellable *cancellable,
+ GError **error)
+{
gboolean res;
gsize read_count, bytes_read;
- char *data;
g_assert (dsi_header != NULL);
-
- input = g_io_stream_get_input_stream (priv->conn);
read_count = sizeof (DSIHeader);
res = g_input_stream_read_all (input, dsi_header, read_count, &bytes_read,
- NULL, NULL);
+ cancellable, error);
if (!res || bytes_read < read_count)
- return NULL;
+ return FALSE;
dsi_header->requestID = GUINT16_FROM_BE (dsi_header->requestID);
dsi_header->errorCode = GUINT32_FROM_BE (dsi_header->errorCode);
dsi_header->totalDataLength = GUINT32_FROM_BE (dsi_header->totalDataLength);
- data = g_malloc (dsi_header->totalDataLength);
+ if (dsi_header->totalDataLength == 0)
+ {
+ *data = NULL;
+ return TRUE;
+ }
+
+ *data = g_malloc (dsi_header->totalDataLength);
read_count = dsi_header->totalDataLength;
- res = g_input_stream_read_all (input, data, read_count, &bytes_read, cancellable, error);
+ res = g_input_stream_read_all (input, *data, read_count, &bytes_read, cancellable, error);
if (!res || bytes_read < read_count)
{
- g_free (data);
- return NULL;
+ g_free (*data);
+ return FALSE;
}
- return data;
+ return TRUE;
+}
+
+GVfsAfpReply *
+g_vfs_afp_connection_read_reply_sync (GVfsAfpConnection *afp_connection,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
+ gboolean res;
+ char *data;
+ DSIHeader dsi_header;
+
+ res = read_reply_sync (g_io_stream_get_input_stream (priv->conn), &dsi_header,
+ &data, cancellable, error);
+ if (!res)
+ return NULL;
+
+ return g_vfs_afp_reply_new (dsi_header.errorCode, data, dsi_header.totalDataLength);
}
static gboolean
-send_request_sync (GVfsAfpConnection *afp_connection,
+send_request_sync (GOutputStream *output,
DsiCommand command,
+ guint16 request_id,
guint32 writeOffset,
gsize len,
char *data,
- guint16 *request_id,
GCancellable *cancellable,
GError **error)
{
- GVfsAfpConnectionPrivate *priv = afp_connection->priv;
-
- GOutputStream *output;
- guint16 req_id;
DSIHeader dsi_header;
gboolean res;
gsize write_count, bytes_written;
- output = g_io_stream_get_output_stream (priv->conn);
-
- req_id = get_request_id (afp_connection);
- if (request_id)
- *request_id = get_request_id (afp_connection);
-
dsi_header.flags = 0x00;
dsi_header.command = command;
- dsi_header.requestID = GUINT16_TO_BE (req_id);
+ dsi_header.requestID = GUINT16_TO_BE (request_id);
dsi_header.writeOffset = GUINT32_TO_BE (writeOffset);
dsi_header.totalDataLength = GUINT32_TO_BE (len);
dsi_header.reserved = 0;
@@ -301,7 +651,7 @@ send_request_sync (GVfsAfpConnection *afp_connection,
if (data == NULL)
return TRUE;
-
+
write_count = len;
res = g_output_stream_write_all (output, data, write_count, &bytes_written,
cancellable, error);
@@ -311,39 +661,21 @@ send_request_sync (GVfsAfpConnection *afp_connection,
return TRUE;
}
-GVfsAfpReply *
-g_vfs_afp_connection_read_reply_sync (GVfsAfpConnection *afp_connection,
- GCancellable *cancellable,
- GError **error)
-{
- char *data;
- DSIHeader dsi_header;
-
- data = read_reply_sync (afp_connection, &dsi_header, cancellable, error);
- if (!data)
- return NULL;
-
- return g_vfs_afp_reply_new (dsi_header.errorCode, data, dsi_header.totalDataLength);
-}
-
gboolean
g_vfs_afp_connection_send_command_sync (GVfsAfpConnection *afp_connection,
GVfsAfpCommand *afp_command,
GCancellable *cancellable,
GError **error)
{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+
DsiCommand dsi_command;
+ guint16 req_id;
guint32 writeOffset;
- GMemoryOutputStream *mem_stream;
/* set dsi_command */
switch (afp_command->type)
{
- case AFP_COMMAND_GET_SRVR_INFO:
- writeOffset = 0;
- dsi_command = DSI_GET_STATUS;
- break;
-
case AFP_COMMAND_WRITE:
writeOffset = 8;
dsi_command = DSI_WRITE;
@@ -356,48 +688,50 @@ g_vfs_afp_connection_send_command_sync (GVfsAfpConnection *afp_connection,
default:
writeOffset = 0;
dsi_command = DSI_COMMAND;
+ break;
}
- mem_stream =
- G_MEMORY_OUTPUT_STREAM(g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (afp_command)));
-
- return send_request_sync (afp_connection, dsi_command, writeOffset,
- g_memory_output_stream_get_size (mem_stream),
- g_memory_output_stream_get_data (mem_stream),
- NULL, cancellable, error);
+ req_id = get_request_id (afp_connection);
+ return send_request_sync (g_io_stream_get_output_stream (priv->conn),
+ dsi_command, req_id, writeOffset,
+ g_vfs_afp_command_get_size (afp_command),
+ g_vfs_afp_command_get_data (afp_command),
+ cancellable, error);
}
-GVfsAfpConnection *
-g_vfs_afp_connection_new (GSocketConnectable *addr,
- GCancellable *cancellable,
- GError **error)
+gboolean
+g_vfs_afp_connection_open (GVfsAfpConnection *afp_connection,
+ GCancellable *cancellable,
+ GError **error)
{
- GVfsAfpConnection *afp_connection;
- GVfsAfpConnectionPrivate *priv;
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
GSocketClient *client;
+ guint16 req_id;
+ gboolean res;
char *reply;
DSIHeader dsi_header;
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));
+ priv->conn = G_IO_STREAM (g_socket_client_connect (client, priv->addr, cancellable, error));
g_object_unref (client);
if (!priv->conn)
- goto error;
+ return FALSE;
- if (!send_request_sync (afp_connection, DSI_OPEN_SESSION, 0, 0, NULL, NULL,
- cancellable, error))
- goto error;
+ req_id = get_request_id (afp_connection);
+ res = send_request_sync (g_io_stream_get_output_stream (priv->conn),
+ DSI_OPEN_SESSION, req_id, 0, 0, NULL,
+ cancellable, error);
+ if (!res)
+ return FALSE;
- reply = read_reply_sync (afp_connection, &dsi_header, cancellable, error);
- if (!reply)
- goto error;
+ res = read_reply_sync (g_io_stream_get_input_stream (priv->conn),
+ &dsi_header, &reply, cancellable, error);
+ if (!res)
+ return FALSE;
pos = 0;
while ((dsi_header.totalDataLength - pos) > 2)
@@ -430,12 +764,63 @@ g_vfs_afp_connection_new (GSocketConnectable *addr,
pos += optionLength;
}
+ g_free (reply);
+
+ return TRUE;
+}
+
+GVfsAfpReply *
+g_vfs_afp_connection_get_server_info (GVfsAfpConnection *afp_connection,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsAfpConnectionPrivate *priv = afp_connection->priv;
- return afp_connection;
+ GSocketClient *client;
+ GIOStream *conn;
+ gboolean res;
+ DSIHeader dsi_header;
+ char *data;
+
+ client = g_socket_client_new ();
+ conn = G_IO_STREAM (g_socket_client_connect (client, priv->addr, cancellable, error));
+ g_object_unref (client);
+
+ if (!conn)
+ return NULL;
-error:
- g_object_unref (afp_connection);
- return NULL;
+ res = send_request_sync (g_io_stream_get_output_stream (conn), DSI_GET_STATUS,
+ 0, 0, 0, NULL, cancellable, error);
+ if (!res)
+ {
+ g_object_unref (conn);
+ return NULL;
+ }
+
+ res = read_reply_sync (g_io_stream_get_input_stream (conn), &dsi_header,
+ &data, cancellable, error);
+ if (!res)
+ {
+ g_object_unref (conn);
+ return NULL;
+ }
+
+ return g_vfs_afp_reply_new (dsi_header.errorCode, data,
+ dsi_header.totalDataLength);
+}
+
+GVfsAfpConnection *
+g_vfs_afp_connection_new (GSocketConnectable *addr)
+{
+ GVfsAfpConnection *afp_connection;
+ GVfsAfpConnectionPrivate *priv;
+
+ afp_connection = g_object_new (G_VFS_TYPE_AFP_CONNECTION, NULL);
+ priv = afp_connection->priv;
+
+ priv->addr = g_object_ref (addr);
+
+ return afp_connection;
}
static void
@@ -447,11 +832,19 @@ g_vfs_afp_connection_init (GVfsAfpConnection *afp_connection)
G_VFS_TYPE_AFP_CONNECTION,
GVfsAfpConnectionPrivate);
+ priv->addr = NULL;
priv->conn = NULL;
priv->request_id = 0;
priv->kRequestQuanta = -1;
priv->kServerReplayCacheSize = -1;
+
+ priv->request_queue = g_queue_new ();
+ priv->request_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify)free_request_data);
+
+ priv->send_loop_running = FALSE;
+ priv->read_loop_running = FALSE;
}
static void
@@ -460,6 +853,9 @@ g_vfs_afp_connection_finalize (GObject *object)
GVfsAfpConnection *afp_connection = (GVfsAfpConnection *)object;
GVfsAfpConnectionPrivate *priv = afp_connection->priv;
+ if (priv->addr)
+ g_object_unref (priv->addr);
+
if (priv->conn)
g_object_unref (priv->conn);
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
index 47bbf0c..4c1d518 100644
--- a/daemon/gvfsafpconnection.h
+++ b/daemon/gvfsafpconnection.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
typedef enum
{
AFP_COMMAND_GET_SRVR_INFO = 15,
+ AFP_COMMAND_GET_SRVR_PARMS = 16,
AFP_COMMAND_LOGIN = 18,
AFP_COMMAND_WRITE = 33,
AFP_COMMAND_WRITE_EXT = 61
@@ -38,6 +39,7 @@ typedef enum
typedef enum
{
AFP_ERROR_NONE = 0,
+ AFP_ERROR_USER_NOT_AUTH = -5023,
AFP_ERROR_NO_MORE_SESSIONS = -1068
} AfpErrorCode;
@@ -76,10 +78,13 @@ typedef struct _GVfsAfpCommandClass GVfsAfpCommandClass;
typedef struct _GVfsAfpCommand GVfsAfpCommand;
-GVfsAfpCommand* g_vfs_afp_command_new (AfpCommandType type);
+GVfsAfpCommand* g_vfs_afp_command_new (AfpCommandType type);
-void g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, char *str);
+void g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, const char *str);
+void g_vfs_afp_command_pad_to_even (GVfsAfpCommand *command);
+gsize g_vfs_afp_command_get_size (GVfsAfpCommand *command);
+char* g_vfs_afp_command_get_data (GVfsAfpCommand *command);
GType g_vfs_afp_command_get_type (void) G_GNUC_CONST;
@@ -90,11 +95,11 @@ GType g_vfs_afp_command_get_type (void) G_GNUC_CONST;
* GVfsAfpConnection
*/
#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))
+#define G_VFS_AFP_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_VFS_TYPE_AFP_CONNECTION, GVfsAfpConnection))
+#define G_VFS_AFP_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_VFS_TYPE_AFP_CONNECTION, GVfsAfpConnectionClass))
+#define G_IS_VFS_AFP_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_VFS_TYPE_AFP_CONNECTION))
+#define G_IS_VFS_AFP_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_VFS_TYPE_AFP_CONNECTION))
+#define G_VFS_AFP_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_VFS_TYPE_AFP_CONNECTION, GVfsAfpConnectionClass))
typedef struct _GVfsAfpConnectionClass GVfsAfpConnectionClass;
typedef struct _GVfsAfpConnection GVfsAfpConnection;
@@ -111,12 +116,24 @@ struct _GVfsAfpConnection
GVfsAfpConnectionPrivate *priv;
};
-
+
+typedef void (*GVfsAfpConnectionReplyCallback) (GVfsAfpConnection *afp_connection,
+ GVfsAfpReply *reply,
+ GError *error,
+ gpointer user_data);
+
+
GType g_vfs_afp_connection_get_type (void) G_GNUC_CONST;
-GVfsAfpConnection* g_vfs_afp_connection_new (GSocketConnectable *addr,
- GCancellable *cancellable,
- GError **error);
+GVfsAfpConnection* g_vfs_afp_connection_new (GSocketConnectable *addr);
+
+GVfsAfpReply* g_vfs_afp_connection_get_server_info (GVfsAfpConnection *afp_connection,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean g_vfs_afp_connection_open (GVfsAfpConnection *afp_connection,
+ GCancellable *cancellable,
+ GError **error);
gboolean g_vfs_afp_connection_send_command_sync (GVfsAfpConnection *afp_connection,
GVfsAfpCommand *afp_command,
@@ -126,6 +143,12 @@ gboolean g_vfs_afp_connection_send_command_sync (GVfsAfpConnection *af
GVfsAfpReply* g_vfs_afp_connection_read_reply_sync (GVfsAfpConnection *afp_connection,
GCancellable *cancellable,
GError **error);
+
+void g_vfs_afp_connection_queue_command (GVfsAfpConnection *afp_connection,
+ GVfsAfpCommand *command,
+ GVfsAfpConnectionReplyCallback reply_cb,
+ GCancellable *cancellable,
+ gpointer user_data);
G_END_DECLS
#endif /* _GVFSAFPCONNECTION_H_ */
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index 6185264..6a723ae 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -28,6 +28,7 @@
#include <gio/gio.h>
#include "gvfsjobmount.h"
+#include "gvfsjobenumerate.h"
#include "gvfsbackendafp.h"
@@ -36,17 +37,272 @@
G_DEFINE_TYPE (GVfsBackendAfp, g_vfs_backend_afp, G_VFS_TYPE_BACKEND);
+
+#define AFP_UAM_NO_USER "No User Authent"
+#define AFP_UAM_DHX "DHCAST128"
+#define AFP_UAM_DHX2 "DHX2"
+
+static const char *
+afp_version_to_string (AfpVersion afp_version)
+{
+ const char *version_strings[] = { "AFPX03", "AFP3.1", "AFP3.2", "AFP3.3" };
+
+ return version_strings[afp_version - 1];
+}
+
+static AfpVersion
+string_to_afp_version (const char *str)
+{
+ gint i;
+
+ const char *version_strings[] = { "AFPX03", "AFP3.1", "AFP3.2", "AFP3.3" };
+
+ for (i = 0; i < G_N_ELEMENTS (version_strings); i++)
+ {
+ if (g_str_equal (str, version_strings[i]))
+ return i + 1;
+ }
+
+ return AFP_VERSION_INVALID;
+}
+
static void
-do_unmount (GVfsBackend * backend,
- GVfsJobUnmount *job,
- GMountUnmountFlags flags,
- GMountSource *mount_source)
+get_srvr_parms_cb (GVfsAfpConnection *afp_connection,
+ GVfsAfpReply *reply,
+ GError *error,
+ gpointer user_data)
{
- GVfsBackendAfp *afp = G_VFS_BACKEND_AFP (backend);
+ GVfsJobEnumerate *job = G_VFS_JOB_ENUMERATE (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
- g_object_unref (afp->conn);
+ AfpErrorCode error_code;
+ guint16 num_volumes, i;
+
+ if (!reply)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ return;
+ }
+
+ error_code = g_vfs_afp_reply_get_error_code (reply);
+ if (error_code != AFP_ERROR_NONE)
+ {
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_FAILED, _("Volume enumeration failed"));
+ return;
+ }
+
+ /* server time */
+ (void)g_data_input_stream_read_int32 (G_DATA_INPUT_STREAM (reply), NULL, NULL);
+
+ num_volumes = g_data_input_stream_read_uint16 (G_DATA_INPUT_STREAM (reply), NULL, NULL);
+ for (i = 0; i < num_volumes; i++)
+ {
+ guint8 flags;
+ char *vol_name;
+
+ GFileInfo *info;
+ GMountSpec *mount_spec;
+ char *uri;
+
+ flags = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (reply), NULL, NULL);
+ vol_name = g_vfs_afp_reply_read_pascal (reply);
+
+ info = g_file_info_new ();
+
+ g_file_info_set_name (info, vol_name);
+ g_file_info_set_display_name (info, vol_name);
+ g_file_info_set_edit_name (info, vol_name);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL, TRUE);
+ g_file_info_set_content_type (info, "inode/directory");
+ g_file_info_set_file_type (info, G_FILE_TYPE_MOUNTABLE);
+
+ g_file_info_set_attribute_boolean (info, "afp::volume-password-protected", (flags & 0x01));
+
+ mount_spec = g_mount_spec_new ("afp-volume");
+ g_mount_spec_set (mount_spec, "host",
+ g_network_address_get_hostname (G_NETWORK_ADDRESS (afp_backend->addr)));
+ g_mount_spec_set (mount_spec, "volume", vol_name);
+
+ if (g_mount_tracker_has_mount_spec (afp_backend->mount_tracker, mount_spec))
+ {
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, FALSE);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, TRUE);
+ }
+ else
+ {
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, TRUE);
+ g_file_info_set_attribute_boolean(info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, FALSE);
+ }
+ g_mount_spec_unref (mount_spec);
+
+ uri = g_strdup_printf ("afp://%s/%s",
+ g_network_address_get_hostname (G_NETWORK_ADDRESS (afp_backend->addr)),
+ vol_name);
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
+ uri);
+ g_free (uri);
+
+ g_vfs_job_enumerate_add_info (job, info);
+ g_object_unref (info);
+ }
+
+ g_vfs_job_enumerate_done (job);
+}
+
+
+static gboolean
+is_root (const char *filename)
+{
+ const char *p;
+
+ p = filename;
+ while (*p == '/')
+ p++;
+
+ return *p == 0;
+}
+
+static gboolean
+try_enumerate (GVfsBackend *backend,
+ GVfsJobEnumerate *job,
+ const char *filename,
+ GFileAttributeMatcher *attribute_matcher,
+ GFileQueryInfoFlags flags)
+{
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+ GVfsAfpCommand *comm;
+
+ if (!is_root(filename))
+ {
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("File doesn't exist"));
+ return TRUE;
+ }
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_GET_SRVR_PARMS);
+ /* pad byte */
+ g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+
+ g_vfs_afp_connection_queue_command (afp_backend->conn, comm,
+ get_srvr_parms_cb,
+ G_VFS_JOB (job)->cancellable, job);
+
+ return TRUE;
}
+static gboolean
+do_login (GVfsBackendAfp *afp_backend,
+ const char *username,
+ const char *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* anonymous login */
+ if (!username)
+ {
+ GVfsAfpCommand *comm;
+ GVfsAfpReply *reply;
+ guint32 error_code;
+
+ if (!g_slist_find_custom (afp_backend->uams, AFP_UAM_NO_USER, g_str_equal))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Server \"%s\" doesn't support anonymous login"),
+ afp_backend->server_name);
+ return FALSE;
+ }
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_LOGIN);
+
+ g_vfs_afp_command_put_pascal (comm,
+ afp_version_to_string (afp_backend->version));
+ g_vfs_afp_command_put_pascal (comm, AFP_UAM_NO_USER);
+ if (!g_vfs_afp_connection_send_command_sync (afp_backend->conn, comm,
+ cancellable, error))
+ return FALSE;
+
+ reply = g_vfs_afp_connection_read_reply_sync (afp_backend->conn, cancellable, error);
+ if (!reply)
+ return FALSE;
+
+ error_code = g_vfs_afp_reply_get_error_code (reply);
+ g_object_unref (reply);
+
+ if (error_code != AFP_ERROR_NONE)
+ {
+ if (error_code == AFP_ERROR_USER_NOT_AUTH)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Anonymous login on server \"%s\" failed"),
+ afp_backend->server_name);
+ return FALSE;
+ }
+ else
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Login to server \"%s\" failed"), afp_backend->server_name);
+ return FALSE;
+ }
+ }
+ }
+
+ else {
+
+ /* Diffie-Hellman 2 */
+ if (g_slist_find_custom (afp_backend->uams, AFP_UAM_DHX2, g_str_equal))
+ {
+ g_debug ("Diffie-Hellman 2\n");
+ }
+
+ /* Diffie-Hellman */
+ else if (g_slist_find_custom (afp_backend->uams, AFP_UAM_DHX, g_str_equal))
+ {
+ g_debug ("Diffie-Hellman\n");
+ }
+
+ else
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Login to server \"%s\" failed, no suitable authentication mechanism found"),
+ afp_backend->server_name);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+try_query_info (GVfsBackend *backend,
+ GVfsJobQueryInfo *job,
+ const char *filename,
+ GFileQueryInfoFlags flags,
+ GFileInfo *info,
+ GFileAttributeMatcher *matcher)
+{
+ g_debug ("filename: %s\n", filename);
+
+ if (is_root (filename))
+ {
+ GIcon *icon;
+
+ g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+ g_file_info_set_name (info, "/");
+ g_file_info_set_display_name (info, g_vfs_backend_get_display_name (backend));
+ g_file_info_set_content_type (info, "inode/directory");
+ icon = g_vfs_backend_get_icon (backend);
+ if (icon != NULL)
+ g_file_info_set_icon (info, icon);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ else
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ return TRUE;
+}
static void
do_mount (GVfsBackend *backend,
GVfsJobMount *job,
@@ -56,37 +312,26 @@ do_mount (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- GError *err;
- GVfsAfpCommand *command;
+ gboolean res;
+ GError *err = NULL;
GVfsAfpReply *reply;
guint16 MachineType_offset, AFPVersionCount_offset, UAMCount_offset;
guint16 VolumeIconAndMask_offset, Flags;
- char *ServerName;
-
- /* UAM */
- guint8 UAMCount;
- GSList *UAMS = NULL;
+ guint8 count;
guint i;
- err = NULL;
- afp_backend->conn = g_vfs_afp_connection_new (afp_backend->addr,
- G_VFS_JOB (job)->cancellable,
- &err);
- if (!afp_backend->conn)
- goto error;
-
- command = g_vfs_afp_command_new (AFP_COMMAND_GET_SRVR_INFO);
- if (!g_vfs_afp_connection_send_command_sync (afp_backend->conn, command,
- G_VFS_JOB (job)->cancellable, &err))
- goto error;
+ GMountSpec *afp_mount_spec;
+ char *display_name;
- reply = g_vfs_afp_connection_read_reply_sync (afp_backend->conn,
+ afp_backend->conn = g_vfs_afp_connection_new (afp_backend->addr);
+
+ reply = g_vfs_afp_connection_get_server_info (afp_backend->conn,
G_VFS_JOB (job)->cancellable,
&err);
if (!reply)
goto error;
-
+
MachineType_offset =
g_data_input_stream_read_uint16 (G_DATA_INPUT_STREAM (reply), NULL, NULL);
AFPVersionCount_offset =
@@ -98,86 +343,75 @@ do_mount (GVfsBackend *backend,
Flags =
g_data_input_stream_read_uint16 (G_DATA_INPUT_STREAM (reply), NULL, NULL);
- ServerName = g_vfs_afp_reply_read_pascal (reply);
- g_debug ("ServerName: %s\n", ServerName);
- g_free (ServerName);
+ afp_backend->server_name = g_vfs_afp_reply_read_pascal (reply);
/* Parse Versions */
g_vfs_afp_reply_seek (reply, AFPVersionCount_offset, G_SEEK_SET);
- UAMCount =
- g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (reply), NULL, NULL);
- g_debug ("Versions\n");
- for (i = 0; i < UAMCount; i++)
+ count = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (reply), NULL, NULL);
+ for (i = 0; i < count; i++)
{
char *version;
+ AfpVersion afp_version;
version = g_vfs_afp_reply_read_pascal (reply);
- g_debug ("%d. %s\n",i + 1, version);
- g_free (version);
+ afp_version = string_to_afp_version (version);
+ if (afp_version > afp_backend->version)
+ afp_backend->version = afp_version;
+ }
+
+ if (afp_backend->version == AFP_VERSION_INVALID)
+ {
+ g_object_unref (reply);
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Failed to connect to server (%s)"), "Server doesn't support AFP version 3.0 or later");
+ return;
}
/* Parse UAMs */
g_vfs_afp_reply_seek (reply, UAMCount_offset, G_SEEK_SET);
- UAMCount =
- g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (reply), NULL, NULL);
- for (i = 0; i < UAMCount; i++)
+ count = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (reply), NULL, NULL);
+ for (i = 0; i < count; i++)
{
- char *UAM;
+ char *uam;
- UAM = g_vfs_afp_reply_read_pascal (reply);
- UAMS = g_slist_prepend (UAMS, UAM);
+ uam = g_vfs_afp_reply_read_pascal (reply);
+ g_debug ("%s\n", uam);
+ afp_backend->uams = g_slist_prepend (afp_backend->uams, uam);
}
-
g_object_unref (reply);
- /* Anonymous login */
- if (!afp_backend->user)
- {
- if (!g_slist_find_custom (UAMS, "No User Authent", g_str_equal))
- {
- g_slist_free_full (UAMS, g_free);
-
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Failed to mount AFP share (%s)"), "Server doesn't support anonymous login");
- return;
- }
+ /* Open connection */
+ res = g_vfs_afp_connection_open (afp_backend->conn, G_VFS_JOB (job)->cancellable,
+ &err);
+ if (!res)
+ goto error;
-
- }
- else
- {
- if (g_slist_find_custom (UAMS, "DHX2", g_str_equal))
- {
- g_debug ("Diffie-Hellman 2\n");
- }
+ res = do_login (afp_backend, NULL, NULL, G_VFS_JOB (job)->cancellable,
+ &err);
+ if (!res)
+ goto error;
- else if (g_slist_find_custom (UAMS, "DHCAST128", g_str_equal))
- {
- g_debug ("Diffie-Hellman");
- }
+ /* set mount info */
+ afp_mount_spec = g_mount_spec_new ("afp");
+ g_mount_spec_set (afp_mount_spec, "host",
+ g_network_address_get_hostname (G_NETWORK_ADDRESS (afp_backend->addr)));
+ if (afp_backend->user)
+ g_mount_spec_set (afp_mount_spec, "user", afp_backend->user);
- else if (g_slist_find_custom (UAMS, "No User Authent", g_str_equal))
- {
- g_debug ("Anonymous login");
- }
+ g_vfs_backend_set_mount_spec (backend, afp_mount_spec);
+ g_mount_spec_unref (afp_mount_spec);
+
+ display_name = g_strdup_printf (_("AFP shares on %s"), afp_backend->server_name);
+ g_vfs_backend_set_display_name (backend, display_name);
+ g_free (display_name);
- else
- {
- g_slist_free_full (UAMS, g_free);
-
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Failed to mount AFP share (%s)"),
- "No suitable authentication mechanism found");
- return;
- }
- }
+ g_vfs_backend_set_icon_name (backend, "network-server-afp");
- g_slist_free_full (UAMS, g_free);
-
+
g_vfs_job_succeeded (G_VFS_JOB (job));
+ return;
error:
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -221,14 +455,23 @@ try_mount (GVfsBackend *backend,
static void
g_vfs_backend_afp_init (GVfsBackendAfp *object)
{
- /* TODO: Add initialization code here */
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (object);
+
+ afp_backend->mount_tracker = g_mount_tracker_new (NULL);
+
+ afp_backend->server_name = NULL;
+ afp_backend->uams = NULL;
+ afp_backend->version = AFP_VERSION_INVALID;
}
static void
g_vfs_backend_afp_finalize (GObject *object)
{
- /* TODO: Add deinitalization code here */
-
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (object);
+
+ g_free (afp_backend->server_name);
+ g_slist_free_full (afp_backend->uams, g_free);
+
G_OBJECT_CLASS (g_vfs_backend_afp_parent_class)->finalize (object);
}
@@ -242,6 +485,7 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
backend_class->try_mount = try_mount;
backend_class->mount = do_mount;
- backend_class->unmount = do_unmount;
+ backend_class->try_query_info = try_query_info;
+ backend_class->try_enumerate = try_enumerate;
}
diff --git a/daemon/gvfsbackendafp.h b/daemon/gvfsbackendafp.h
index ac9cd12..03d73bd 100644
--- a/daemon/gvfsbackendafp.h
+++ b/daemon/gvfsbackendafp.h
@@ -25,10 +25,21 @@
#include <gvfsbackend.h>
+#include "gmounttracker.h"
+
#include "gvfsafpconnection.h"
G_BEGIN_DECLS
+typedef enum
+{
+ AFP_VERSION_INVALID,
+ AFP_VERSION_3_0,
+ AFP_VERSIOM_3_1,
+ AFP_VERSION_3_2,
+ AFP_VERSION_3_3
+} AfpVersion;
+
#define G_VFS_TYPE_BACKEND_AFP (g_vfs_backend_afp_get_type ())
#define G_VFS_BACKEND_AFP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_VFS_TYPE_BACKEND_AFP, GVfsBackendAfp))
#define G_VFS_BACKEND_AFP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_VFS_TYPE_BACKEND_AFP, GVfsBackendAfpClass))
@@ -51,7 +62,12 @@ struct _GVfsBackendAfp
GSocketConnectable *addr;
char *user;
+ GMountTracker *mount_tracker;
GVfsAfpConnection *conn;
+
+ char *server_name;
+ GSList *uams;
+ AfpVersion version;
};
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]