[gvfs] afp: add read support
- From: Christian Kellner <gicmo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] afp: add read support
- Date: Thu, 25 Aug 2011 19:23:48 +0000 (UTC)
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]