summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--daemon/Makefile.am8
-rw-r--r--daemon/gvfsafpconnection.c40
-rw-r--r--daemon/gvfsafpconnection.h1
-rw-r--r--daemon/gvfsafpserver.c499
-rw-r--r--daemon/gvfsafpserver.h25
-rw-r--r--daemon/gvfsafputils.c12
-rw-r--r--daemon/gvfsafputils.h10
-rw-r--r--daemon/gvfsafpvolume.c3033
-rw-r--r--daemon/gvfsafpvolume.h281
-rw-r--r--daemon/gvfsbackendafp.c2643
-rw-r--r--daemon/gvfsbackendafpbrowse.c12
11 files changed, 4001 insertions, 2563 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 954b67eb..55cf029e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -485,7 +485,9 @@ gvfsd_afp_browse_SOURCES = \
gvfsafpconnection.h \
gvfsafpconnection.c \
gvfsafpserver.h \
- gvfsafpserver.c
+ gvfsafpserver.c \
+ gvfsafpvolume.h \
+ gvfsafpvolume.c
gvfsd_afp_browse_CPPFLAGS = \
-DBACKEND_HEADER=gvfsbackendafpbrowse.h \
@@ -505,7 +507,9 @@ gvfsd_afp_SOURCES = \
gvfsafpconnection.h \
gvfsafpconnection.c \
gvfsafpserver.h \
- gvfsafpserver.c
+ gvfsafpserver.c \
+ gvfsafpvolume.h \
+ gvfsafpvolume.c
gvfsd_afp_CPPFLAGS = \
-DBACKEND_HEADER=gvfsbackendafp.h \
diff --git a/daemon/gvfsafpconnection.c b/daemon/gvfsafpconnection.c
index 5c2312db..be489c54 100644
--- a/daemon/gvfsafpconnection.c
+++ b/daemon/gvfsafpconnection.c
@@ -511,6 +511,46 @@ g_vfs_afp_command_put_afp_name (GVfsAfpCommand *comm, GVfsAfpName *afp_name)
}
}
+static GVfsAfpName *
+filename_to_afp_pathname (const char *filename)
+{
+ gsize len;
+ char *str;
+ gint i;
+
+ while (*filename == '/')
+ filename++;
+
+ len = strlen (filename);
+
+ str = g_malloc (len);
+
+ for (i = 0; i < len; i++)
+ {
+ if (filename[i] == '/')
+ str[i] = '\0';
+ else
+ str[i] = filename[i];
+ }
+
+
+ return g_vfs_afp_name_new (0x08000103, str, len);
+}
+
+void
+g_vfs_afp_command_put_pathname (GVfsAfpCommand *comm, const char *filename)
+{
+ GVfsAfpName *pathname;
+
+ /* PathType */
+ g_vfs_afp_command_put_byte (comm, AFP_PATH_TYPE_UTF8_NAME);
+
+ /* Pathname */
+ pathname = filename_to_afp_pathname (filename);
+ g_vfs_afp_command_put_afp_name (comm, pathname);
+ g_vfs_afp_name_unref (pathname);
+}
+
void
g_vfs_afp_command_pad_to_even (GVfsAfpCommand *comm)
{
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
index d02b1f80..f70ff2e0 100644
--- a/daemon/gvfsafpconnection.h
+++ b/daemon/gvfsafpconnection.h
@@ -303,6 +303,7 @@ void g_vfs_afp_command_put_uint64 (GVfsAfpCommand *comm, guint64 v
void g_vfs_afp_command_put_pascal (GVfsAfpCommand *comm, const char *str);
void g_vfs_afp_command_put_afp_name (GVfsAfpCommand *comm, GVfsAfpName *afp_name);
+void g_vfs_afp_command_put_pathname (GVfsAfpCommand *comm, const char *filename);
void g_vfs_afp_command_pad_to_even (GVfsAfpCommand *comm);
diff --git a/daemon/gvfsafpserver.c b/daemon/gvfsafpserver.c
index 6ecd18e7..8dbd3077 100644
--- a/daemon/gvfsafpserver.c
+++ b/daemon/gvfsafpserver.c
@@ -841,6 +841,82 @@ get_server_parms (GVfsAfpServer *server,
return TRUE;
}
+static gboolean
+get_userinfo (GVfsAfpServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsAfpCommand *comm;
+ guint16 bitmap;
+ gboolean res;
+
+ GVfsAfpReply *reply;
+ AfpResultCode res_code;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_GET_USER_INFO);
+ /* Flags, ThisUser = 1 */
+ g_vfs_afp_command_put_byte (comm, 0x01);
+ /* UserId */
+ g_vfs_afp_command_put_int32 (comm, 0);
+ /* Bitmap */
+ bitmap = AFP_GET_USER_INFO_BITMAP_GET_UID_BIT | AFP_GET_USER_INFO_BITMAP_GET_GID_BIT;
+ g_vfs_afp_command_put_uint16 (comm, bitmap);
+
+ res = g_vfs_afp_connection_send_command_sync (server->conn,
+ comm, cancellable, error);
+ g_object_unref (comm);
+ if (!res)
+ return FALSE;
+
+ reply = g_vfs_afp_connection_read_reply_sync (server->conn,
+ cancellable, error);
+ if (!reply)
+ return FALSE;
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ break;
+ case AFP_RESULT_CALL_NOT_SUPPORTED:
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Command is not supported by server"));
+ break;
+ case AFP_RESULT_PWD_EXPIRED_ERR:
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("User's password has expired"));
+ break;
+ case AFP_RESULT_PWD_NEEDS_CHANGE_ERR:
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("User's password needs to be changed"));
+ break;
+
+ default:
+ g_propagate_error (error, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ return FALSE;
+ }
+
+ /* Bitmap */
+ g_vfs_afp_reply_read_uint16 (reply, NULL);
+ /* UID */
+ g_vfs_afp_reply_read_uint32 (reply, &server->user_id);
+ /* GID */
+ g_vfs_afp_reply_read_uint32 (reply, &server->group_id);
+
+ g_object_unref (reply);
+
+ return TRUE;
+}
+
gboolean
g_vfs_afp_server_login (GVfsAfpServer *server,
const char *initial_user,
@@ -982,14 +1058,16 @@ try_login:
g_free (olduser);
if (!res)
- {
- g_free (user);
- g_free (password);
+ goto error;
- g_propagate_error (error, err);
- return FALSE;
- }
+ /* Get server parms */
+ if (!get_server_parms (server, cancellable, &err))
+ goto error;
+ /* Get user info */
+ if (!get_userinfo (server, cancellable, &err))
+ goto error;
+
if (prompt && !anonymous)
{
/* a prompt was created, so we have to save the password */
@@ -1004,10 +1082,6 @@ try_login:
password_save);
g_free (prompt);
}
-
- /* Get server parms */
- if (!get_server_parms (server, cancellable, error))
- return FALSE;
if (logged_in_user)
{
@@ -1022,6 +1096,12 @@ try_login:
g_free (password);
return TRUE;
+
+error:
+ g_free (user);
+ g_free (password);
+ g_propagate_error (error, err);
+ return FALSE;
}
/*
@@ -1039,174 +1119,6 @@ g_vfs_afp_server_time_to_local_time (GVfsAfpServer *server,
return server_time + server->time_diff;
}
-static void
-get_vol_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *connection = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
- GVfsAfpServer *server = G_VFS_AFP_SERVER (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- guint16 vol_bitmap;
- GFileInfo *info;
-
- reply = g_vfs_afp_connection_send_command_finish (connection, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
-
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- goto done;
- }
-
- g_vfs_afp_reply_read_uint16 (reply, &vol_bitmap);
-
- info = g_file_info_new ();
-
- if (vol_bitmap & AFP_VOLUME_BITMAP_ATTRIBUTE_BIT)
- {
- guint16 vol_attrs_bitmap;
-
- g_vfs_afp_reply_read_uint16 (reply, &vol_attrs_bitmap);
-
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
- vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_READ_ONLY);
- }
-
- if (vol_bitmap & AFP_VOLUME_BITMAP_CREATE_DATE_BIT)
- {
- gint32 create_date;
- gint64 create_date_local;
-
- g_vfs_afp_reply_read_int32 (reply, &create_date);
-
- create_date_local = g_vfs_afp_server_time_to_local_time (server, create_date);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED,
- create_date_local);
- }
-
- if (vol_bitmap & AFP_VOLUME_BITMAP_MOD_DATE_BIT)
- {
- gint32 mod_date;
- gint64 mod_date_local;
-
- g_vfs_afp_reply_read_int32 (reply, &mod_date);
-
- mod_date_local = g_vfs_afp_server_time_to_local_time (server, mod_date);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED,
- mod_date_local);
- }
-
- if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_FREE_BIT)
- {
- guint64 bytes_free;
-
- g_vfs_afp_reply_read_uint64 (reply, &bytes_free);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
- bytes_free);
- }
-
- if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT)
- {
- guint64 bytes_total;
-
- g_vfs_afp_reply_read_uint64 (reply, &bytes_total);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
- bytes_total);
- }
-
- g_object_unref (reply);
-
- g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-/*
- * g_vfs_afp_server_get_vol_parms:
- *
- * @server: a #GVfsAfpServer
- * @volume_id: id of the volume whose parameters should be received.
- * @vol_bitmap: bitmap describing the parameters that should be received.
- * @cancellable: optional #GCancellable object, %NULL to ignore.
- * @callback: callback to call when the request is satisfied.
- * @user_data: the data to pass to callback function.
- *
- * Asynchronously retrives the parameters specified by @vol_bitmap of the volume
- * with id @volume_id.
- */
-void
-g_vfs_afp_server_get_vol_parms (GVfsAfpServer *server,
- guint16 volume_id,
- guint16 vol_bitmap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_GET_VOL_PARMS);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, volume_id);
- /* Volume Bitmap */
- g_vfs_afp_command_put_uint16 (comm, vol_bitmap);
-
- simple = g_simple_async_result_new (G_OBJECT (server), callback, user_data,
- g_vfs_afp_server_get_vol_parms);
-
-
- g_vfs_afp_connection_send_command (server->conn, comm, NULL, get_vol_parms_cb,
- cancellable, simple);
- g_object_unref (comm);
-}
-
-/*
- * g_vfs_afp_server_get_vol_parms_finish:
- *
- * @server: a #GVfsAfpServer.
- * @result: a #GAsyncResult.
- * @error: a #GError, %NULL to ignore.
- *
- * Finalizes the asynchronous operation started by
- * g_vfs_afp_server_get_vol_parms.
- *
- * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
- * on error.
- */
-GFileInfo *
-g_vfs_afp_server_get_vol_parms_finish (GVfsAfpServer *server,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (server),
- g_vfs_afp_server_get_vol_parms),
- NULL);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
-
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
-}
static void
volume_data_free (GVfsAfpVolumeData *vol_data)
@@ -1312,7 +1224,7 @@ g_vfs_afp_server_get_volumes (GVfsAfpServer *server,
}
/*
- * g_vfs_afp_server_get_vol_parms_finish:
+ * g_vfs_afp_server_get_volumes_finish:
*
* @server: a #GVfsAfpServer.
* @result: a #GAsyncResult.
@@ -1343,4 +1255,233 @@ g_vfs_afp_server_get_volumes_finish (GVfsAfpServer *server,
return NULL;
return g_ptr_array_ref ((GPtrArray *)g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+GVfsAfpVolume *
+g_vfs_afp_server_mount_volume_sync (GVfsAfpServer *server,
+ const char *volume_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsAfpVolume *volume;
+
+ volume = g_vfs_afp_volume_new (server);
+ if (!g_vfs_afp_volume_mount_sync (volume, volume_name, cancellable, error))
+ {
+ g_object_unref (volume);
+ return NULL;
+ }
+
+ return volume;
+}
+
+static void
+set_access_attributes_trusted (GFileInfo *info,
+ guint32 perm)
+{
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
+ perm & 0x4);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
+ perm & 0x2);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
+ perm & 0x1);
+}
+
+/* For files we don't own we can't trust a negative response to this check, as
+ something else could allow us to do the operation, for instance an ACL
+ or some sticky bit thing */
+static void
+set_access_attributes (GFileInfo *info,
+ guint32 perm)
+{
+ if (perm & 0x4)
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
+ TRUE);
+ if (perm & 0x2)
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
+ TRUE);
+ if (perm & 0x1)
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
+ TRUE);
+}
+
+void
+g_vfs_afp_server_fill_info (GVfsAfpServer *server,
+ GFileInfo *info,
+ GVfsAfpReply *reply,
+ gboolean directory,
+ guint16 bitmap)
+{
+ goffset start_pos;
+
+ if (directory)
+ {
+ GIcon *icon;
+
+ g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+ g_file_info_set_content_type (info, "inode/directory");
+
+ icon = g_themed_icon_new ("folder");
+ g_file_info_set_icon (info, icon);
+ g_object_unref (icon);
+ }
+ else
+ g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
+
+
+ start_pos = g_vfs_afp_reply_get_pos (reply);
+
+ if (bitmap & AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT)
+ {
+ guint16 attributes;
+
+ g_vfs_afp_reply_read_uint16 (reply, &attributes);
+
+ if (attributes & AFP_FILEDIR_ATTRIBUTES_BITMAP_INVISIBLE_BIT)
+ g_file_info_set_is_hidden (info, TRUE);
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT)
+ {
+ guint32 parent_dir_id;
+
+ g_vfs_afp_reply_read_uint32 (reply, &parent_dir_id);
+ g_file_info_set_attribute_uint32 (info, "afp::parent-dir-id", parent_dir_id);
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_CREATE_DATE_BIT)
+ {
+ gint32 create_date;
+ gint64 create_date_local;
+
+ g_vfs_afp_reply_read_int32 (reply, &create_date);
+
+ create_date_local = g_vfs_afp_server_time_to_local_time (server, create_date);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED,
+ create_date_local);
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_MOD_DATE_BIT)
+ {
+ gint32 mod_date;
+ guint64 mod_date_unix;
+ char *etag;
+
+ g_vfs_afp_reply_read_int32 (reply, &mod_date);
+ mod_date_unix = g_vfs_afp_server_time_to_local_time (server, mod_date);
+
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ mod_date_unix);
+
+ etag = g_strdup_printf ("%"G_GUINT64_FORMAT, mod_date_unix);
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag);
+ g_free (etag);
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_NODE_ID_BIT)
+ {
+ guint32 node_id;
+
+ g_vfs_afp_reply_read_uint32 (reply, &node_id);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID, node_id);
+ }
+
+ /* Directory specific attributes */
+ if (directory)
+ {
+ if (bitmap & AFP_DIR_BITMAP_OFFSPRING_COUNT_BIT)
+ {
+ guint16 offspring_count;
+
+ g_vfs_afp_reply_read_uint16 (reply, &offspring_count);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_CHILDREN_COUNT,
+ offspring_count);
+ }
+ }
+
+ /* File specific attributes */
+ else
+ {
+ if (bitmap & AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT)
+ {
+ guint64 fork_len;
+
+ g_vfs_afp_reply_read_uint64 (reply, &fork_len);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ fork_len);
+ }
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_UTF8_NAME_BIT)
+ {
+ guint16 UTF8Name_offset;
+ goffset old_pos;
+ GVfsAfpName *afp_name;
+ char *utf8_name;
+
+ g_vfs_afp_reply_read_uint16 (reply, &UTF8Name_offset);
+ /* Pad */
+ g_vfs_afp_reply_read_uint32 (reply, NULL);
+
+ old_pos = g_vfs_afp_reply_get_pos (reply);
+ g_vfs_afp_reply_seek (reply, start_pos + UTF8Name_offset, G_SEEK_SET);
+
+ g_vfs_afp_reply_read_afp_name (reply, TRUE, &afp_name);
+ utf8_name = g_vfs_afp_name_get_string (afp_name);
+ g_vfs_afp_name_unref (afp_name);
+
+ g_file_info_set_name (info, utf8_name);
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+ utf8_name);
+
+ /* Set file as hidden if it begins with a dot */
+ if (utf8_name[0] == '.')
+ g_file_info_set_is_hidden (info, TRUE);
+
+ if (!directory)
+ {
+ char *content_type;
+ GIcon *icon;
+
+ content_type = g_content_type_guess (utf8_name, NULL, 0, NULL);
+ g_file_info_set_content_type (info, content_type);
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
+ content_type);
+
+ icon = g_content_type_get_icon (content_type);
+ g_file_info_set_icon (info, icon);
+
+ g_object_unref (icon);
+ g_free (content_type);
+ }
+
+ g_free (utf8_name);
+
+ g_vfs_afp_reply_seek (reply, old_pos, G_SEEK_SET);
+ }
+
+ if (bitmap & AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT)
+ {
+ guint32 uid, gid, permissions, ua_permissions;
+
+ g_vfs_afp_reply_read_uint32 (reply, &uid);
+ g_vfs_afp_reply_read_uint32 (reply, &gid);
+ g_vfs_afp_reply_read_uint32 (reply, &permissions);
+ /* ua_permissions */
+ g_vfs_afp_reply_read_uint32 (reply, &ua_permissions);
+
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, permissions);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, uid);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, gid);
+
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_UA_PERMISSIONS,
+ ua_permissions);
+
+ if (uid == server->user_id)
+ set_access_attributes_trusted (info, (permissions >> 6) & 0x7);
+ else if (gid == server->group_id)
+ set_access_attributes (info, (permissions >> 3) & 0x7);
+ else
+ set_access_attributes (info, (permissions >> 0) & 0x7);
+ }
} \ No newline at end of file
diff --git a/daemon/gvfsafpserver.h b/daemon/gvfsafpserver.h
index 0688ff10..25753cab 100644
--- a/daemon/gvfsafpserver.h
+++ b/daemon/gvfsafpserver.h
@@ -27,6 +27,7 @@
#include "gmountsource.h"
#include "gvfsafpconnection.h"
+#include "gvfsafpvolume.h"
G_BEGIN_DECLS
@@ -69,6 +70,9 @@ struct _GVfsAfpServer
AfpVersion version;
gint32 time_diff;
+
+ guint32 user_id;
+ guint32 group_id;
};
GType g_vfs_afp_server_get_type (void) G_GNUC_CONST;
@@ -85,16 +89,6 @@ gboolean g_vfs_afp_server_login (GVfsAfpServer *afp_ser
gint64 g_vfs_afp_server_time_to_local_time (GVfsAfpServer *afp_serv,
gint32 server_time);
-void g_vfs_afp_server_get_vol_parms (GVfsAfpServer *server,
- guint16 volume_id,
- guint16 vol_bitmap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-GFileInfo * g_vfs_afp_server_get_vol_parms_finish (GVfsAfpServer *server,
- GAsyncResult *result,
- GError **error);
-
typedef struct _GVfsAfpVolumeData GVfsAfpVolumeData;
struct _GVfsAfpVolumeData
{
@@ -110,6 +104,17 @@ GPtrArray * g_vfs_afp_server_get_volumes_finish (GVfsAfpServer *server
GAsyncResult *result,
GError **error);
+GVfsAfpVolume * g_vfs_afp_server_mount_volume_sync (GVfsAfpServer *server,
+ const char *volume_name,
+ GCancellable *cancellable,
+ GError **error);
+
+void g_vfs_afp_server_fill_info (GVfsAfpServer *server,
+ GFileInfo *info,
+ GVfsAfpReply *reply,
+ gboolean directory,
+ guint16 bitmap);
+
G_END_DECLS
#endif /* _GVFSAFPSERVER_H_ */
diff --git a/daemon/gvfsafputils.c b/daemon/gvfsafputils.c
index 9d0872db..7875390b 100644
--- a/daemon/gvfsafputils.c
+++ b/daemon/gvfsafputils.c
@@ -126,3 +126,15 @@ afp_result_code_to_gerror (AfpResultCode res_code)
return g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
_("Got unknown error code %d from server"), res_code);
}
+
+gboolean
+is_root (const char *filename)
+{
+ const char *p;
+
+ p = filename;
+ while (*p == '/')
+ p++;
+
+ return *p == 0;
+}
diff --git a/daemon/gvfsafputils.h b/daemon/gvfsafputils.h
index 467cc13f..6f4388e9 100644
--- a/daemon/gvfsafputils.h
+++ b/daemon/gvfsafputils.h
@@ -82,8 +82,14 @@ typedef enum
AFP_RESULT_DISK_QUOTA_EXCEEDED = -5047
} AfpResultCode;
-GError *
-afp_result_code_to_gerror (AfpResultCode res_code);
+#define G_FILE_ATTRIBUTE_AFP_NODE_ID "afp::node-id"
+#define G_FILE_ATTRIBUTE_AFP_PARENT_DIR_ID "afp::parent-dir-id"
+#define G_FILE_ATTRIBUTE_AFP_CHILDREN_COUNT "afp::children-count"
+#define G_FILE_ATTRIBUTE_AFP_UA_PERMISSIONS "afp::ua-permisssions"
+
+GError *afp_result_code_to_gerror (AfpResultCode res_code);
+
+gboolean is_root (const char *filename);
G_END_DECLS
diff --git a/daemon/gvfsafpvolume.c b/daemon/gvfsafpvolume.c
new file mode 100644
index 00000000..5bc60324
--- /dev/null
+++ b/daemon/gvfsafpvolume.c
@@ -0,0 +1,3033 @@
+ /* 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 <glib/gi18n.h>
+
+#include "gvfsafpserver.h"
+
+#include "gvfsafpvolume.h"
+
+
+
+G_DEFINE_TYPE (GVfsAfpVolume, g_vfs_afp_volume, G_TYPE_OBJECT);
+
+struct _GVfsAfpVolumePrivate
+{
+ GVfsAfpServer *server;
+ gboolean mounted;
+
+ guint16 attributes;
+ guint16 volume_id;
+};
+
+static void
+g_vfs_afp_volume_init (GVfsAfpVolume *volume)
+{
+ GVfsAfpVolumePrivate *priv;
+
+ volume->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (volume, G_VFS_TYPE_AFP_VOLUME,
+ GVfsAfpVolumePrivate);
+ priv->mounted = FALSE;
+}
+
+static void
+g_vfs_afp_volume_finalize (GObject *object)
+{
+ /* TODO: Add deinitalization code here */
+
+ G_OBJECT_CLASS (g_vfs_afp_volume_parent_class)->finalize (object);
+}
+
+static void
+g_vfs_afp_volume_class_init (GVfsAfpVolumeClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = g_vfs_afp_volume_finalize;
+
+ g_type_class_add_private (klass, sizeof (GVfsAfpVolumePrivate));
+}
+
+GVfsAfpVolume *
+g_vfs_afp_volume_new (GVfsAfpServer *server)
+{
+ GVfsAfpVolume *volume;
+ GVfsAfpVolumePrivate *priv;
+
+ g_return_val_if_fail (G_VFS_IS_AFP_SERVER (server), NULL);
+
+ volume = g_object_new (G_VFS_TYPE_AFP_VOLUME, NULL);
+ priv = volume->priv;
+
+ priv->server = server;
+
+ return volume;
+}
+
+gboolean
+g_vfs_afp_volume_mount_sync (GVfsAfpVolume *volume,
+ const char *volume_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GVfsAfpReply *reply;
+ gboolean res;
+ AfpResultCode res_code;
+
+ g_return_val_if_fail (G_VFS_IS_AFP_VOLUME (volume), FALSE);
+ g_return_val_if_fail (volume_name != NULL, FALSE);
+
+ priv = volume->priv;
+
+ /* Open Volume */
+ comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_VOL);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* Volume Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, AFP_VOLUME_BITMAP_VOL_ID_BIT | AFP_VOLUME_BITMAP_ATTRIBUTE_BIT);
+
+ /* VolumeName */
+ g_vfs_afp_command_put_pascal (comm, volume_name);
+
+ /* TODO: password? */
+
+ res = g_vfs_afp_connection_send_command_sync (priv->server->conn, comm, cancellable,
+ error);
+ g_object_unref (comm);
+ if (!res)
+ return FALSE;
+
+ reply = g_vfs_afp_connection_read_reply_sync (priv->server->conn, cancellable, error);
+ if (!reply)
+ return FALSE;
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+ goto generic_error;
+ }
+
+ /* Volume Bitmap */
+ g_vfs_afp_reply_read_uint16 (reply, NULL);
+ /* Volume Attributes Bitmap */
+ g_vfs_afp_reply_read_uint16 (reply, &priv->attributes);
+ /* Volume ID */
+ g_vfs_afp_reply_read_uint16 (reply, &priv->volume_id);
+
+ g_object_unref (reply);
+
+ priv->mounted = TRUE;
+ return TRUE;
+
+generic_error:
+ /* Translators: first %s is volumename and second servername */
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Couldn't mount AFP volume %s on %s"), volume_name,
+ priv->server->server_name);
+ return FALSE;
+}
+
+guint16
+g_vfs_afp_volume_get_attributes (GVfsAfpVolume *volume)
+{
+ GVfsAfpVolumePrivate *priv = volume->priv;
+
+ g_return_val_if_fail (priv->mounted, 0);
+
+ return priv->attributes;
+}
+
+guint16
+g_vfs_afp_volume_get_id (GVfsAfpVolume *volume)
+{
+ GVfsAfpVolumePrivate *priv = volume->priv;
+
+ g_return_val_if_fail (priv->mounted, 0);
+
+ return priv->volume_id;
+}
+
+static void
+get_vol_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *connection = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ GVfsAfpVolumePrivate *priv = volume->priv;
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ guint16 vol_bitmap;
+ GFileInfo *info;
+
+ reply = g_vfs_afp_connection_send_command_finish (connection, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ goto done;
+ }
+
+ g_vfs_afp_reply_read_uint16 (reply, &vol_bitmap);
+
+ info = g_file_info_new ();
+
+ if (vol_bitmap & AFP_VOLUME_BITMAP_ATTRIBUTE_BIT)
+ {
+ guint16 vol_attrs_bitmap;
+
+ g_vfs_afp_reply_read_uint16 (reply, &vol_attrs_bitmap);
+
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
+ vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_READ_ONLY);
+ }
+
+ if (vol_bitmap & AFP_VOLUME_BITMAP_CREATE_DATE_BIT)
+ {
+ gint32 create_date;
+ gint64 create_date_local;
+
+ g_vfs_afp_reply_read_int32 (reply, &create_date);
+
+ create_date_local = g_vfs_afp_server_time_to_local_time (priv->server, create_date);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED,
+ create_date_local);
+ }
+
+ if (vol_bitmap & AFP_VOLUME_BITMAP_MOD_DATE_BIT)
+ {
+ gint32 mod_date;
+ gint64 mod_date_local;
+
+ g_vfs_afp_reply_read_int32 (reply, &mod_date);
+
+ mod_date_local = g_vfs_afp_server_time_to_local_time (priv->server, mod_date);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ mod_date_local);
+ }
+
+ if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_FREE_BIT)
+ {
+ guint64 bytes_free;
+
+ g_vfs_afp_reply_read_uint64 (reply, &bytes_free);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
+ bytes_free);
+ }
+
+ if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT)
+ {
+ guint64 bytes_total;
+
+ g_vfs_afp_reply_read_uint64 (reply, &bytes_total);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
+ bytes_total);
+ }
+
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_get_parms:
+ *
+ * @volume: a #GVfsAfpVolume
+ * @vol_bitmap: bitmap describing the parameters that should be received.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously retrieves the parameters specified by @vol_bitmap from @volume
+ */
+void
+g_vfs_afp_volume_get_parms (GVfsAfpVolume *volume,
+ guint16 vol_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_GET_VOL_PARMS);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, priv->volume_id);
+ /* Volume Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, vol_bitmap);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_get_parms);
+
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL, get_vol_parms_cb,
+ cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_get_parms_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_get_parms.
+ *
+ * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
+ * on error.
+ */
+GFileInfo *
+g_vfs_afp_volume_get_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_get_parms),
+ NULL);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+typedef struct
+{
+ gint16 fork_refnum;
+ GFileInfo *info;
+} OpenForkData;
+
+static void
+open_fork_data_free (OpenForkData *data)
+{
+ g_object_unref (data->info);
+
+ g_slice_free (OpenForkData, data);
+}
+
+static void
+open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpVolume *volume;
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ OpenForkData *data;
+ guint16 file_bitmap;
+
+ volume = G_VFS_AFP_VOLUME (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ priv = volume->priv;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("File doesn't exist"));
+ break;
+ case AFP_RESULT_OBJECT_TYPE_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("File is directory"));
+ break;
+ case AFP_RESULT_TOO_MANY_FILES_OPEN:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_TOO_MANY_OPEN_FILES,
+ _("Too many files open"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+ data = g_slice_new (OpenForkData);
+
+ g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+ g_vfs_afp_reply_read_int16 (reply, &data->fork_refnum);
+
+ data->info = g_file_info_new ();
+ g_vfs_afp_server_fill_info (priv->server, data->info, reply, FALSE, file_bitmap);
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, data,
+ (GDestroyNotify)open_fork_data_free);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_open_fork:
+ *
+ * @volume: a #GVfsAfpVolume
+ * @filename: file to open fork for.
+ * @access_mode:
+ * @bitmap:
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously opens a fork corresponding to @filename with the requested
+ * access rights.
+ */
+void
+g_vfs_afp_volume_open_fork (GVfsAfpVolume *volume,
+ const char *filename,
+ guint16 access_mode,
+ guint16 bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ if (is_root (filename))
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (volume), callback,
+ user_data, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("File is directory"));
+ return;
+ }
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_FORK);
+ /* data fork */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, bitmap);
+
+ /* AccessMode */
+ g_vfs_afp_command_put_uint16 (comm, access_mode);
+
+ /* Pathname */
+ g_vfs_afp_command_put_pathname (comm, filename);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_open_fork);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ open_fork_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_open_fork_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @fork_refnum: (out) the reference id of the newly opened fork.
+ * @info: (out callee-allocates) a #GFileInfo containing the requested parameters.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_open_fork.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_open_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gint16 *fork_refnum,
+ GFileInfo **info,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ OpenForkData *data;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_open_fork),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ if (fork_refnum)
+ *fork_refnum = data->fork_refnum;
+ if (info)
+ *info = g_object_ref (data->info);
+
+ return TRUE;
+}
+
+static void
+close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_close_fork:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @fork_refnum: the reference id of the fork which is to be closed.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously closes an open fork specified by @fork_refnum.
+ */
+void
+g_vfs_afp_volume_close_fork (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_CLOSE_FORK);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* OForkRefNum */
+ g_vfs_afp_command_put_int16 (comm, fork_refnum);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_close_fork);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ close_fork_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_close_fork_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_close_fork.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_close_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_close_fork),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_FILE_BUSY:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("Target file is open"));
+ break;
+ case AFP_RESULT_DIR_NOT_EMPTY:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY,
+ _("Directory not empty"));
+ break;
+ case AFP_RESULT_OBJECT_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Target object is marked as not deletable (DeleteInhibit)"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Target object doesn't exist"));
+ break;
+ case AFP_RESULT_VOL_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Volume is read-only"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_delete:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @filename: file to delete.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously deletes the file @filename.
+ */
+void
+g_vfs_afp_volume_delete (GVfsAfpVolume *volume,
+ const char *filename,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_DELETE);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* Pathname */
+ g_vfs_afp_command_put_pathname (comm, filename);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_delete);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ delete_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_delete_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_delete.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_delete_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_delete),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+typedef struct
+{
+ char *filename;
+ gboolean hard_create;
+ GCancellable *cancellable;
+} CreateFileData;
+
+static void
+create_file_data_free (CreateFileData *cfd)
+{
+ g_free (cfd->filename);
+ if (cfd->cancellable)
+ g_object_unref (cfd->cancellable);
+
+ g_slice_free (CreateFileData, cfd);
+}
+
+static void
+create_file_cb (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_DISK_FULL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space on volume"));
+ break;
+ case AFP_RESULT_FILE_BUSY:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file is open"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file already exists"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Ancestor directory doesn't exist"));
+ break;
+ case AFP_RESULT_VOL_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Volume is read-only"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+create_file_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
+ GVfsAfpVolumePrivate *priv = volume->priv;
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ CreateFileData *cfd = g_simple_async_result_get_op_res_gpointer (simple);
+
+ GFileInfo *info;
+ GError *err = NULL;
+
+ guint32 dir_id;
+ char *basename;
+ GVfsAfpCommand *comm;
+
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
+ if (!info)
+ {
+ g_simple_async_result_take_error (simple, err);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
+ g_object_unref (info);
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_FILE);
+ /* soft/hard create */
+ g_vfs_afp_command_put_byte (comm, cfd->hard_create ? 0x80 : 0x00);
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID */
+ g_vfs_afp_command_put_uint32 (comm, dir_id);
+
+ /* Pathname */
+ basename = g_path_get_basename (cfd->filename);
+ g_vfs_afp_command_put_pathname (comm, basename);
+ g_free (basename);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ create_file_cb, cfd->cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_create_file:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @filename: path to the new file to create.
+ * @hard_create: if %TRUE this call will overwrite an already existing file.
+ * If %FALSE it will error out instead.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously creates a file at @filename.
+ */
+void
+g_vfs_afp_volume_create_file (GVfsAfpVolume *volume,
+ const char *filename,
+ gboolean hard_create,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ CreateFileData *cfd;
+ GSimpleAsyncResult *simple;
+ char *dirname;
+
+ cfd = g_slice_new0 (CreateFileData);
+ cfd->filename = g_strdup (filename);
+ cfd->hard_create = hard_create;
+ if (cancellable)
+ cfd->cancellable = g_object_ref (cancellable);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_create_file);
+ g_simple_async_result_set_op_res_gpointer (simple, cfd,
+ (GDestroyNotify)create_file_data_free);
+
+ dirname = g_path_get_dirname (filename);
+ g_vfs_afp_volume_get_filedir_parms (volume, dirname, 0, AFP_DIR_BITMAP_NODE_ID_BIT,
+ cancellable, create_file_get_filedir_parms_cb, simple);
+ g_free (dirname);
+}
+
+/*
+ * g_vfs_afp_volume_create_file_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_create_file.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_create_file_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_create_file),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+typedef struct
+{
+ char *basename;
+ GCancellable *cancellable;
+} CreateDirData;
+
+static void
+create_dir_data_free (CreateDirData *cdd)
+{
+ g_free (cdd->basename);
+ g_object_unref (cdd->cancellable);
+
+ g_slice_free (CreateDirData, cdd);
+}
+
+static void
+make_directory_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_DISK_FULL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space on volume"));
+ break;
+ case AFP_RESULT_FLAT_VOL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Volume is flat and doesn't support directories"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Ancestor directory doesn't exist"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target directory already exists"));
+ break;
+ case AFP_RESULT_VOL_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Volume is read-only"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+create_directory_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ CreateDirData *cdd = g_simple_async_result_get_op_res_gpointer (simple);
+
+ GFileInfo *info = NULL;
+ GError *err = NULL;
+
+ guint32 dir_id;
+ GVfsAfpCommand *comm;
+
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
+ if (!info)
+ goto error;
+
+ if (g_cancellable_set_error_if_cancelled (cdd->cancellable, &err))
+ goto error;
+
+ dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
+ g_object_unref (info);
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_DIR);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID */
+ g_vfs_afp_command_put_uint32 (comm, dir_id);
+
+ /* Pathname */
+ g_vfs_afp_command_put_pathname (comm, cdd->basename);
+
+ g_vfs_afp_connection_send_command (volume->priv->server->conn, comm, NULL,
+ make_directory_cb, cdd->cancellable, simple);
+ g_object_unref (comm);
+ return;
+
+error:
+ g_clear_object (info);
+ g_simple_async_result_take_error (simple, err);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_create_directory:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @directory: path to the new directory to create.
+ * @hard_create: if %TRUE this call will overwrite an already existing file.
+ * If %FALSE it will error out instead.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously creates a directory at @directory.
+ */
+void
+g_vfs_afp_volume_create_directory (GVfsAfpVolume *volume,
+ const char *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ CreateDirData *cdd;
+ char *dirname;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_create_directory);
+
+ cdd = g_slice_new (CreateDirData);
+ cdd->basename = g_path_get_basename (directory);
+ cdd->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+ g_simple_async_result_set_op_res_gpointer (simple, cdd,
+ (GDestroyNotify)create_dir_data_free);
+
+ dirname = g_path_get_dirname (directory);
+ g_vfs_afp_volume_get_filedir_parms (volume, dirname, 0,
+ AFP_DIR_BITMAP_NODE_ID_BIT,
+ cancellable,
+ create_directory_get_filedir_parms_cb,
+ simple);
+ g_free (dirname);
+}
+
+/*
+ * g_vfs_afp_volume_create_directory_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_create_directory.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_create_directory_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_create_directory),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+typedef struct
+{
+ char *filename;
+ char *new_name;
+ GCancellable *cancellable;
+} RenameData;
+
+static void
+rename_data_free (RenameData *rd)
+{
+ g_free (rd->filename);
+ g_free (rd->new_name);
+ g_object_unref (rd->cancellable);
+
+ g_slice_free (RenameData, rd);
+}
+
+static void
+rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_CANT_RENAME:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
+ _("Can't rename volume"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Object with that name already exists"));
+ break;
+ case AFP_RESULT_OBJECT_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Target object is marked as not renameable (RenameInhibit)"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Target object doesn't exist"));
+ break;
+ case AFP_RESULT_VOL_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Volume is read-only"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+rename_get_filedir_parms_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ RenameData *rd = g_simple_async_result_get_op_res_gpointer (simple);
+
+ GFileInfo *info;
+ GError *err = NULL;
+
+ guint32 dir_id;
+ GVfsAfpCommand *comm;
+ char *basename;
+
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
+ if (!info)
+ {
+ g_simple_async_result_take_error (simple, err);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_PARENT_DIR_ID);
+ g_object_unref (info);
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_RENAME);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID */
+ g_vfs_afp_command_put_uint32 (comm, dir_id);
+
+ /* Pathname */
+ basename = g_path_get_basename (rd->filename);
+ g_vfs_afp_command_put_pathname (comm, basename);
+ g_free (basename);
+
+ /* NewName */
+ g_vfs_afp_command_put_pathname (comm, rd->new_name);
+
+ g_vfs_afp_connection_send_command (volume->priv->server->conn, comm, NULL,
+ rename_cb, rd->cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_rename:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @filename: path to file to rename.
+ * @new_name: the new name of the file.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously renames the file at @filename to @new_name.
+ */
+void
+g_vfs_afp_volume_rename (GVfsAfpVolume *volume,
+ const char *filename,
+ const char *new_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ RenameData *rd;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_rename);
+
+ rd = g_slice_new (RenameData);
+ rd->filename = g_strdup (filename);
+ rd->new_name = g_strdup (new_name);
+ rd->cancellable = g_object_ref (cancellable);
+ g_simple_async_result_set_op_res_gpointer (simple, rd,
+ (GDestroyNotify)rename_data_free);
+
+ g_vfs_afp_volume_get_filedir_parms (volume, filename,
+ AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
+ AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
+ cancellable, rename_get_filedir_parms_cb,
+ simple);
+}
+
+/*
+ * g_vfs_afp_volume_rename_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_move_and_rename.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_rename_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_rename),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_CANT_MOVE:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
+ _("Can't move directory into one of its descendants"));
+ break;
+ case AFP_RESULT_INSIDE_SHARE_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can't move sharepoint into a shared directory"));
+ break;
+ case AFP_RESULT_INSIDE_TRASH_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can't move a shared directory into the Trash"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file already exists"));
+ break;
+ case AFP_RESULT_OBJECT_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Object being moved is marked as not renameable (RenameInhibit)"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Object being moved doesn't exist"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_move_and_rename:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @source: the source path of the file to move.
+ * @destination: destination path.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously moves (and renames) the file at @source to @destination.
+ */
+void
+g_vfs_afp_volume_move_and_rename (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ char *dirname, *basename;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_MOVE_AND_RENAME);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* VolumeID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+
+ /* SourceDirectoryID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+ /* DestDirectoryID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* SourcePathname */
+ g_vfs_afp_command_put_pathname (comm, source);
+
+ /* DestPathname */
+ dirname = g_path_get_dirname (destination);
+ g_vfs_afp_command_put_pathname (comm, dirname);
+ g_free (dirname);
+
+ /* NewName */
+ basename = g_path_get_basename (destination);
+ g_vfs_afp_command_put_pathname (comm, basename);
+ g_free (basename);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_move_and_rename);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ move_and_rename_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_move_and_rename_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_move_and_rename.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_move_and_rename_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_move_and_rename),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+copy_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_CALL_NOT_SUPPORTED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Server doesn't support the FPCopyFile operation"));
+ break;
+ case AFP_RESULT_DENY_CONFLICT:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to open source file for reading"));
+ break;
+ case AFP_RESULT_DISK_FULL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space on volume"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file already exists"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Source file and/or destination directory doesn't exist"));
+ break;
+ case AFP_RESULT_OBJECT_TYPE_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("Source file is a directory"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_copy_file:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @source: the source path of the file to copy.
+ * @destination: destination path.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously copies the file at @source to @destination.
+ */
+void
+g_vfs_afp_volume_copy_file (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+
+ GVfsAfpCommand *comm;
+ char *dirname, *basename;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_COPY_FILE);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* SourceVolumeID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* SourceDirectoryID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* DestVolumeID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* DestDirectoryID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* SourcePathname */
+ g_vfs_afp_command_put_pathname (comm, source);
+
+ /* DestPathname */
+ dirname = g_path_get_dirname (destination);
+ g_vfs_afp_command_put_pathname (comm, dirname);
+ g_free (dirname);
+
+ /* NewName */
+ basename = g_path_get_basename (destination);
+ g_vfs_afp_command_put_pathname (comm, basename);
+ g_free (basename);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_copy_file);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ copy_file_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_copy_file_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_copy_file.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_copy_file_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_copy_file),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+typedef struct
+{
+ AfpMapIDFunction function;
+ char *name;
+} MapIDData;
+
+static void
+map_id_data_free (MapIDData *mid)
+{
+ g_free (mid->name);
+
+ g_slice_free (MapIDData, mid);
+}
+
+static void
+map_id_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+
+ AfpResultCode res_code;
+ MapIDData *map_data;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ g_simple_async_result_complete (simple);
+ return;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ITEM_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("ID not found"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+
+ g_simple_async_result_complete (simple);
+ return;
+ }
+
+ map_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (map_data->function == AFP_MAP_ID_FUNCTION_USER_UUID_TO_UTF8_NAME ||
+ map_data->function == AFP_MAP_ID_FUNCTION_GROUP_UUID_TO_UTF8_NAME)
+ {
+ /* objType */
+ g_vfs_afp_reply_read_uint32 (reply, NULL);
+ /* id */
+ g_vfs_afp_reply_read_uint32 (reply, NULL);
+ }
+
+ if (map_data->function == AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME ||
+ map_data->function == AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME)
+ {
+ g_vfs_afp_reply_read_pascal (reply, &map_data->name);
+ }
+ else
+ {
+ GVfsAfpName *afp_name;
+
+ g_vfs_afp_reply_read_afp_name (reply, FALSE, &afp_name);
+ map_data->name = g_vfs_afp_name_get_string (afp_name);
+ g_vfs_afp_name_unref (afp_name);
+ }
+
+ g_simple_async_result_complete (simple);
+}
+
+/*
+ * g_vfs_afp_volume_map_id:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @map_function: a #AfpMapIDFunction.
+ * @id: the id to be mapped to a name.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously maps a user id, group id or uuid to a name.
+ */
+void
+g_vfs_afp_volume_map_id (GVfsAfpVolume *volume,
+ AfpMapIDFunction map_function,
+ gint64 id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+ MapIDData *map_data;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_MAP_ID);
+
+ /* SubFunction*/
+ g_vfs_afp_command_put_byte (comm, map_function);
+
+ /* ID */
+ if (map_function == AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME ||
+ map_function == AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME)
+ g_vfs_afp_command_put_int32 (comm, id);
+ else
+ g_vfs_afp_command_put_int64 (comm, id);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_map_id);
+
+ map_data = g_slice_new0 (MapIDData);
+ map_data->function = map_function;
+ g_simple_async_result_set_op_res_gpointer (simple, map_data,
+ (GDestroyNotify)map_id_data_free);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ map_id_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_map_id_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @map_function: (out) optional out parameter to get the #AfpMapIDFunction
+ * which was used, %NULL to ignore.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_map_id.
+ *
+ * Returns: (transfer full): A string with the name of the id or %NULL
+ * on error.
+ */
+char *
+g_vfs_afp_volume_map_id_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ AfpMapIDFunction *map_function,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ MapIDData *map_data;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_map_id),
+ NULL);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ map_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (map_function)
+ *map_function = map_data->function;
+
+ return g_strdup (map_data->name);
+}
+
+static void
+get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ guint16 file_bitmap, dir_bitmap, bitmap;
+ guint8 FileDir;
+ gboolean directory;
+ GFileInfo *info;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("File doesn't exist"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+ g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+ g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
+
+ g_vfs_afp_reply_read_byte (reply, &FileDir);
+ /* Pad Byte */
+ g_vfs_afp_reply_read_byte (reply, NULL);
+
+ directory = (FileDir & 0x80);
+ bitmap = directory ? dir_bitmap : file_bitmap;
+
+ info = g_file_info_new ();
+ g_vfs_afp_server_fill_info (volume->priv->server, info, reply, directory, bitmap);
+
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_get_filedir_parms:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @filename: file or directory whose parameters should be retreived.
+ * @file_bitmap: bitmap describing the parameters to retrieve if @filename is a
+ * file.
+ * @dir_bitmap: bitmap describing the parameters to retrieve if @filename is a
+ * directory.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously retrieves the parameters described by @file_bitmap or
+ * @dir_bitmap of the file/directory at @filename.
+ */
+void
+g_vfs_afp_volume_get_filedir_parms (GVfsAfpVolume *volume,
+ const char *filename,
+ guint16 file_bitmap,
+ guint16 dir_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FILE_DIR_PARMS);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* VolumeID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+ /* FileBitmap */
+ g_vfs_afp_command_put_uint16 (comm, file_bitmap);
+ /* DirectoryBitmap */
+ g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
+ /* PathName */
+ g_vfs_afp_command_put_pathname (comm, filename);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_get_filedir_parms);
+
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ get_filedir_parms_cb, cancellable,
+ simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_get_filedir_parms_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_get_fork_parms.
+ *
+ * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
+ * on error.
+ */
+GFileInfo *
+g_vfs_afp_volume_get_filedir_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_get_filedir_parms),
+ NULL);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+static void
+get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ GVfsAfpVolumePrivate *priv = volume->priv;
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ guint16 file_bitmap;
+ GFileInfo *info;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ goto done;
+ }
+
+ g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+
+ info = g_file_info_new ();
+ g_vfs_afp_server_fill_info (priv->server, info, reply, FALSE, file_bitmap);
+
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_get_fork_parms:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @fork_refnume: the reference id of the fork.
+ * @file_bitmap: bitmap describing the parameters to retrieve.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously retrieves the parameters described by @file_bitmap of the fork
+ * with reference id @fork_refnum.
+ */
+void
+g_vfs_afp_volume_get_fork_parms (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ guint16 file_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FORK_PARMS);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+ /* OForkRefNum */
+ g_vfs_afp_command_put_int16 (comm, fork_refnum);
+ /* Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, file_bitmap);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_get_fork_parms);
+
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ get_fork_parms_cb, cancellable,
+ simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_get_fork_parms_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_get_fork_parms.
+ *
+ * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
+ * on error.
+ */
+GFileInfo *
+g_vfs_afp_volume_get_fork_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_get_fork_parms),
+ NULL);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+static void
+set_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_DISK_FULL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space on volume"));
+ break;
+ case AFP_RESULT_LOCK_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Range lock conflict exists"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_set_fork_size:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @fork_refnume: the reference id of the fork.
+ * @size: the new size of the fork,
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously sets the size of the fork referenced by @fork_refnum.
+ */
+void
+g_vfs_afp_volume_set_fork_size (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ gint64 size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FORK_PARMS);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* OForkRefNum */
+ g_vfs_afp_command_put_int16 (comm, fork_refnum);
+ /* Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT);
+ /* ForkLen */
+ g_vfs_afp_command_put_int64 (comm, size);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_set_fork_size);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ set_fork_parms_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_set_fork_size_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_set_fork_size.
+ *
+ * Returns: (transfer full): %TRUE on success, %FALSE otherwise.
+ */
+gboolean
+g_vfs_afp_volume_set_fork_size_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (volume),
+ g_vfs_afp_volume_set_fork_size),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+set_unix_privs_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Target object doesn't exist"));
+ break;
+ case AFP_RESULT_VOL_LOCKED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Volume is read-only"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_set_unix_privs:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @filename: file or directory whose unix privileges should be set.
+ * @uid: the new user id of the file.
+ * @gid: the new group id of the file.
+ * @permissions: the new unix permissions of the file.
+ * @ua_permissions: the new AFP access right of the file.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously sets new unix permissions on the file/directory pointed to by
+ * @filename.
+ */
+void
+g_vfs_afp_volume_set_unix_privs (GVfsAfpVolume *volume,
+ const char *filename,
+ guint32 uid,
+ guint32 gid,
+ guint32 permissions,
+ guint32 ua_permissions,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FILEDIR_PARMS);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* VolumeID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* DirectoryID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+ /* Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT);
+ /* Pathname */
+ g_vfs_afp_command_put_pathname (comm, filename);
+ /* pad to even */
+ g_vfs_afp_command_pad_to_even (comm);
+
+ /* UID */
+ g_vfs_afp_command_put_uint32 (comm, uid);
+ /* GID */
+ g_vfs_afp_command_put_uint32 (comm, gid);
+ /* Permissions */
+ g_vfs_afp_command_put_uint32 (comm, permissions);
+ /* UAPermissions */
+ g_vfs_afp_command_put_uint32 (comm, ua_permissions);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_set_unix_privs);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ set_unix_privs_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_set_unix_privs_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_set_unix_privs.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_set_unix_privs_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_set_unix_privs),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static const gint16 ENUMERATE_REQ_COUNT = G_MAXINT16;
+static const gint16 ENUMERATE_EXT_MAX_REPLY_SIZE = G_MAXINT16;
+static const gint32 ENUMERATE_EXT2_MAX_REPLY_SIZE = G_MAXINT32;
+
+static void
+enumerate_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ GVfsAfpVolumePrivate *priv = volume->priv;
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ guint16 file_bitmap;
+ guint16 dir_bitmap;
+ gint16 count, i;
+ GPtrArray *infos;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_OBJECT_NOT_FOUND:
+ g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL);
+ break;
+
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_DIR_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Directory doesn't exist"));
+ break;
+ case AFP_RESULT_OBJECT_TYPE_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
+ _("Target object is not a directory"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+ g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+ g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
+
+ g_vfs_afp_reply_read_int16 (reply, &count);
+ infos = g_ptr_array_new_full (count, g_object_unref);
+
+ for (i = 0; i < count; i++)
+ {
+ goffset start_pos;
+ guint16 struct_length;
+ guint8 FileDir;
+
+ gboolean directory;
+ guint16 bitmap;
+ GFileInfo *info;
+
+ start_pos = g_vfs_afp_reply_get_pos (reply);
+
+ g_vfs_afp_reply_read_uint16 (reply, &struct_length);
+ g_vfs_afp_reply_read_byte (reply, &FileDir);
+ /* pad byte */
+ g_vfs_afp_reply_read_byte (reply, NULL);
+
+ directory = (FileDir & 0x80);
+ bitmap = directory ? dir_bitmap : file_bitmap;
+
+ info = g_file_info_new ();
+ g_vfs_afp_server_fill_info (priv->server, info, reply, directory, bitmap);
+ g_ptr_array_add (infos, info);
+
+ g_vfs_afp_reply_seek (reply, start_pos + struct_length, G_SEEK_SET);
+ }
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, infos, NULL);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_enumerate:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously enumerates the files in @directory starting at index
+ * @start_index.
+ */
+void
+g_vfs_afp_volume_enumerate (GVfsAfpVolume *volume,
+ const char *directory,
+ gint64 start_index,
+ guint16 file_bitmap,
+ guint16 dir_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ gint32 max;
+
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback,
+ user_data, g_vfs_afp_volume_enumerate);
+
+ max = (priv->server->version >= AFP_VERSION_3_1) ? G_MAXINT32 : G_MAXINT16;
+ /* Can't enumerate any more files */
+ if (start_index > max)
+ {
+ g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL);
+ g_simple_async_result_complete_in_idle (simple);
+ return;
+ }
+
+ if (priv->server->version >= AFP_VERSION_3_1)
+ comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT2);
+ else
+ comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT);
+
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* Directory ID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* File Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, file_bitmap);
+
+ /* Dir Bitmap */
+ g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
+
+ /* Req Count */
+ g_vfs_afp_command_put_int16 (comm, ENUMERATE_REQ_COUNT);
+
+
+ /* StartIndex and MaxReplySize */
+ if (priv->server->version >= AFP_VERSION_3_1)
+ {
+ g_vfs_afp_command_put_int32 (comm, start_index);
+ g_vfs_afp_command_put_int32 (comm, ENUMERATE_EXT2_MAX_REPLY_SIZE);
+ }
+ else
+ {
+ g_vfs_afp_command_put_int16 (comm, start_index);
+ g_vfs_afp_command_put_int16 (comm, ENUMERATE_EXT_MAX_REPLY_SIZE);
+ }
+
+ /* Pathname */
+ g_vfs_afp_command_put_pathname (comm, directory);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ enumerate_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_enumerate_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @infos: (out) (element-type G.FileInfo): array of #GFileInfo objects or %NULL
+ * when no more files could be found.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_enumerate.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_enumerate_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GPtrArray **infos,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_enumerate),
+ FALSE);
+ g_return_val_if_fail (infos != NULL, FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ *infos = g_simple_async_result_get_op_res_gpointer (simple);
+
+ return TRUE;
+}
+
+static void
+close_replace_exchange_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ g_object_unref (reply);
+
+ if (res_code != AFP_RESULT_NO_ERROR)
+ {
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Permission denied"));
+ break;
+ case AFP_RESULT_ID_NOT_FOUND:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("File doesn't exist"));
+ break;
+ case AFP_RESULT_OBJECT_TYPE_ERR:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("File is directory"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_exchange_files:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @source: path to source file to exchange.
+ * @destination: path to destination file to exchange.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously exchanges the file system metadata of the two files @source
+ * and @destination.
+ */
+void
+g_vfs_afp_volume_exchange_files (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpVolumePrivate *priv;
+ GVfsAfpCommand *comm;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ priv = volume->priv;
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_EXCHANGE_FILES);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* Volume ID */
+ g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
+ /* SourceDirectory ID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+ /* DestDirectory ID 2 == / */
+ g_vfs_afp_command_put_uint32 (comm, 2);
+
+ /* SourcePath */
+ g_vfs_afp_command_put_pathname (comm, source);
+ /* DestPath */
+ g_vfs_afp_command_put_pathname (comm, destination);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_exchange_files);
+
+ g_vfs_afp_connection_send_command (priv->server->conn, comm, NULL,
+ close_replace_exchange_files_cb,
+ cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_exchange_files_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_exchange_files.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_exchange_files_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_exchange_files),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+write_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+ gint64 *last_written;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (!(res_code == AFP_RESULT_NO_ERROR || res_code == AFP_RESULT_LOCK_ERR))
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("File is not open for write access"));
+ break;
+ case AFP_RESULT_DISK_FULL:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space on volume"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+ last_written = g_new (gint64, 1);
+ g_vfs_afp_reply_read_int64 (reply, last_written);
+ g_object_unref (reply);
+
+ g_simple_async_result_set_op_res_gpointer (simple, last_written, g_free);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_write_to_fork:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @fork_refnume: reference id of the fork to write to.
+ * @buffer: buffer containing the data to write. Must be valid during the whole
+ * call.
+ * @buffer_size: size of @buffer.
+ * @offset: offset in file where the data should be written.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously writes the data in @buffer to the fork referenced by
+ * @fork_refnum.
+ */
+void
+g_vfs_afp_volume_write_to_fork (GVfsAfpVolume *volume,
+ guint16 fork_refnum,
+ char *buffer,
+ gsize buffer_size,
+ gint64 offset,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpCommand *comm;
+ guint32 req_count;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_WRITE_EXT);
+ /* StartEndFlag = 0 */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* OForkRefNum */
+ g_vfs_afp_command_put_int16 (comm, fork_refnum);
+ /* Offset */
+ g_vfs_afp_command_put_int64 (comm, offset);
+ /* ReqCount */
+ req_count = MIN (buffer_size, G_MAXUINT32);
+ g_vfs_afp_command_put_int64 (comm, req_count);
+
+ g_vfs_afp_command_set_buffer (comm, buffer, buffer_size);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_write_to_fork);
+
+ g_vfs_afp_connection_send_command (volume->priv->server->conn, comm, NULL,
+ write_ext_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_write_to_fork_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @last_written: (out) (allow-none): offset of the last written byte.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_write_to_fork.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_write_to_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gint64 *last_written,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_write_to_fork),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (last_written)
+ *last_written = *((gint64 *)g_simple_async_result_get_op_res_gpointer (simple));
+
+ return TRUE;
+}
+
+static void
+read_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ GVfsAfpReply *reply;
+ GError *err = NULL;
+ AfpResultCode res_code;
+
+ reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
+ if (!reply)
+ {
+ g_simple_async_result_take_error (simple, err);
+ goto done;
+ }
+
+ res_code = g_vfs_afp_reply_get_result_code (reply);
+ if (!(res_code == AFP_RESULT_NO_ERROR || res_code == AFP_RESULT_LOCK_ERR ||
+ res_code == AFP_RESULT_EOF_ERR))
+ {
+ g_object_unref (reply);
+
+ switch (res_code)
+ {
+ case AFP_RESULT_ACCESS_DENIED:
+ g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("File is not open for read access"));
+ break;
+ default:
+ g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
+ break;
+ }
+ goto done;
+ }
+
+ g_simple_async_result_set_op_res_gssize (simple, g_vfs_afp_reply_get_size (reply));
+ g_object_unref (reply);
+
+done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+/*
+ * g_vfs_afp_volume_read_from_fork:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @fork_refnume: reference id of the fork to write to.
+ * @buffer: buffer to read data into. Must be valid during the whole call.
+ * @bytes_requested: number of bytes that should be read.
+ * @offset: offset in file from where the data should be read.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: callback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously reads data from the fork referenced by @fork_refnum.
+ */
+void
+g_vfs_afp_volume_read_from_fork (GVfsAfpVolume *volume,
+ guint16 fork_refnum,
+ char *buffer,
+ gsize bytes_requested,
+ gint64 offset,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfpCommand *comm;
+ guint32 req_count;
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
+
+ comm = g_vfs_afp_command_new (AFP_COMMAND_READ_EXT);
+ /* pad byte */
+ g_vfs_afp_command_put_byte (comm, 0);
+
+ /* OForkRefNum */
+ g_vfs_afp_command_put_int16 (comm, fork_refnum);
+ /* Offset */
+ g_vfs_afp_command_put_int64 (comm, offset);
+ /* ReqCount */
+ req_count = MIN (bytes_requested, G_MAXUINT32);
+ g_vfs_afp_command_put_int64 (comm, req_count);
+
+ simple = g_simple_async_result_new (G_OBJECT (volume), callback, user_data,
+ g_vfs_afp_volume_read_from_fork);
+
+ g_vfs_afp_connection_send_command (volume->priv->server->conn, comm, buffer,
+ read_ext_cb, cancellable, simple);
+ g_object_unref (comm);
+}
+
+/*
+ * g_vfs_afp_volume_read_from_fork_finish:
+ *
+ * @volume: a #GVfsAfpVolume.
+ * @result: a #GAsyncResult.
+ * @bytes_read: (out) (allow-none): the number of bytes that were read.
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Finalizes the asynchronous operation started by
+ * g_vfs_afp_volume_read_from_fork.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+g_vfs_afp_volume_read_from_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gsize *bytes_read,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (volume),
+ g_vfs_afp_volume_read_from_fork),
+ FALSE);
+
+ simple = (GSimpleAsyncResult *)res;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (bytes_read)
+ *bytes_read = g_simple_async_result_get_op_res_gssize (simple);
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/daemon/gvfsafpvolume.h b/daemon/gvfsafpvolume.h
new file mode 100644
index 00000000..aed9dd7f
--- /dev/null
+++ b/daemon/gvfsafpvolume.h
@@ -0,0 +1,281 @@
+ /* 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 _GVFSAFPVOLUME_H_
+#define _GVFSAFPVOLUME_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GVfsAfpServer GVfsAfpServer;
+
+#define G_VFS_TYPE_AFP_VOLUME (g_vfs_afp_volume_get_type ())
+#define G_VFS_AFP_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_VFS_TYPE_AFP_VOLUME, GVfsAfpVolume))
+#define G_VFS_AFP_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_VFS_TYPE_AFP_VOLUME, GVfsAfpVolumeClass))
+#define G_VFS_IS_AFP_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_VFS_TYPE_AFP_VOLUME))
+#define G_VFS_IS_AFP_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_VFS_TYPE_AFP_VOLUME))
+#define G_VFS_AFP_VOLUME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_VFS_TYPE_AFP_VOLUME, GVfsAfpVolumeClass))
+
+typedef struct _GVfsAfpVolumeClass GVfsAfpVolumeClass;
+typedef struct _GVfsAfpVolume GVfsAfpVolume;
+typedef struct _GVfsAfpVolumePrivate GVfsAfpVolumePrivate;
+
+struct _GVfsAfpVolumeClass
+{
+ GObjectClass parent_class;
+};
+
+struct _GVfsAfpVolume
+{
+ GObject parent_instance;
+
+ GVfsAfpVolumePrivate *priv;
+};
+
+GType g_vfs_afp_volume_get_type (void) G_GNUC_CONST;
+
+GVfsAfpVolume *g_vfs_afp_volume_new (GVfsAfpServer *server);
+
+gboolean g_vfs_afp_volume_mount_sync (GVfsAfpVolume *volume,
+ const char *volume_name,
+ GCancellable *cancellable,
+ GError **error);
+
+guint16 g_vfs_afp_volume_get_attributes (GVfsAfpVolume *volume);
+guint16 g_vfs_afp_volume_get_id (GVfsAfpVolume *volume);
+
+void g_vfs_afp_volume_get_parms (GVfsAfpVolume *volume,
+ guint16 vol_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GFileInfo * g_vfs_afp_volume_get_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_open_fork (GVfsAfpVolume *volume,
+ const char *filename,
+ guint16 access_mode,
+ guint16 bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_open_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gint16 *fork_refnum,
+ GFileInfo **info,
+ GError **error);
+
+void g_vfs_afp_volume_close_fork (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_close_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_delete (GVfsAfpVolume *volume,
+ const char *filename,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_delete_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_create_file (GVfsAfpVolume *volume,
+ const char *filename,
+ gboolean hard_create,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_create_file_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_create_directory (GVfsAfpVolume *volume,
+ const char *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_create_directory_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_copy_file (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_copy_file_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_afp_volume_rename (GVfsAfpVolume *volume,
+ const char *filename,
+ const char *new_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_rename_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_afp_volume_move_and_rename (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_move_and_rename_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_afp_volume_map_id (GVfsAfpVolume *volume,
+ AfpMapIDFunction map_function,
+ gint64 id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+char * g_vfs_afp_volume_map_id_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ AfpMapIDFunction *map_function,
+ GError **error);
+
+void g_vfs_afp_volume_get_filedir_parms (GVfsAfpVolume *volume,
+ const char *filename,
+ guint16 file_bitmap,
+ guint16 dir_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GFileInfo * g_vfs_afp_volume_get_filedir_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_get_fork_parms (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ guint16 file_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GFileInfo * g_vfs_afp_volume_get_fork_parms_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_set_fork_size (GVfsAfpVolume *volume,
+ gint16 fork_refnum,
+ gint64 size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_set_fork_size_finish (GVfsAfpVolume *volume,
+ GAsyncResult *result,
+ GError **error);
+
+void g_vfs_afp_volume_set_unix_privs (GVfsAfpVolume *volume,
+ const char *filename,
+ guint32 uid,
+ guint32 gid,
+ guint32 permissions,
+ guint32 ua_permissions,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_set_unix_privs_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_afp_volume_enumerate (GVfsAfpVolume *volume,
+ const char *directory,
+ gint64 start_index,
+ guint16 file_bitmap,
+ guint16 dir_bitmap,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_enumerate_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GPtrArray **infos,
+ GError **error);
+
+void g_vfs_afp_volume_exchange_files (GVfsAfpVolume *volume,
+ const char *source,
+ const char *destination,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_exchange_files_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_afp_volume_write_to_fork (GVfsAfpVolume *volume,
+ guint16 fork_refnum,
+ char *buffer,
+ gsize buffer_size,
+ gint64 offset,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_write_to_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gint64 *last_written,
+ GError **error);
+
+void g_vfs_afp_volume_read_from_fork (GVfsAfpVolume *volume,
+ guint16 fork_refnum,
+ char *buffer,
+ gsize bytes_requested,
+ gint64 offset,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_vfs_afp_volume_read_from_fork_finish (GVfsAfpVolume *volume,
+ GAsyncResult *res,
+ gsize *bytes_read,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* _GVFSAFPVOLUME_H_ */
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index d35ee7a6..3e790213 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -53,19 +53,9 @@
#include "gvfsjobcopy.h"
#include "gvfsafpserver.h"
-#include "gvfsafpconnection.h"
#include "gvfsbackendafp.h"
-#define G_FILE_ATTRIBUTE_AFP_NODE_ID "afp::node-id"
-#define G_FILE_ATTRIBUTE_AFP_PARENT_DIR_ID "afp::parent-dir-id"
-#define G_FILE_ATTRIBUTE_AFP_CHILDREN_COUNT "afp::children-count"
-#define G_FILE_ATTRIBUTE_AFP_UA_PERMISSIONS "afp::ua-permisssions"
-
-static const gint16 ENUMERATE_REQ_COUNT = G_MAXINT16;
-static const gint16 ENUMERATE_EXT_MAX_REPLY_SIZE = G_MAXINT16;
-static const gint32 ENUMERATE_EXT2_MAX_REPLY_SIZE = G_MAXINT32;
-
struct _GVfsBackendAfpClass
{
GVfsBackendClass parent_class;
@@ -76,13 +66,11 @@ struct _GVfsBackendAfp
GVfsBackend parent_instance;
GNetworkAddress *addr;
- char *volume;
+ char *volume_name;
char *user;
GVfsAfpServer *server;
-
- guint16 vol_attrs_bitmap;
- guint16 volume_id;
+ GVfsAfpVolume *volume;
guint32 user_id;
guint32 group_id;
@@ -95,27 +83,6 @@ G_DEFINE_TYPE (GVfsBackendAfp, g_vfs_backend_afp, G_VFS_TYPE_BACKEND);
/*
* Utility functions
*/
-static void
-job_failed_from_afp_result_code (GVfsJob *job, AfpResultCode res_code)
-{
- GError *err;
-
- err = afp_result_code_to_gerror (res_code);
- g_vfs_job_failed_from_error (job, err);
- g_error_free (err);
-}
-
-static gboolean
-is_root (const char *filename)
-{
- const char *p;
-
- p = filename;
- while (*p == '/')
- p++;
-
- return *p == 0;
-}
static void
copy_file_info_into (GFileInfo *src, GFileInfo *dest)
@@ -137,46 +104,6 @@ copy_file_info_into (GFileInfo *src, GFileInfo *dest)
g_strfreev (attrs);
}
-static GVfsAfpName *
-filename_to_afp_pathname (const char *filename)
-{
- gsize len;
- char *str;
- gint i;
-
- while (*filename == '/')
- filename++;
-
- len = strlen (filename);
-
- str = g_malloc (len);
-
- for (i = 0; i < len; i++)
- {
- if (filename[i] == '/')
- str[i] = '\0';
- else
- str[i] = filename[i];
- }
-
-
- return g_vfs_afp_name_new (0x08000103, str, len);
-}
-
-static void
-put_pathname (GVfsAfpCommand *comm, const char *filename)
-{
- GVfsAfpName *pathname;
-
- /* PathType */
- g_vfs_afp_command_put_byte (comm, AFP_PATH_TYPE_UTF8_NAME);
-
- /* Pathname */
- pathname = filename_to_afp_pathname (filename);
- g_vfs_afp_command_put_afp_name (comm, pathname);
- g_vfs_afp_name_unref (pathname);
-}
-
typedef enum
{
AFP_HANDLE_TYPE_READ_FILE,
@@ -188,6 +115,8 @@ typedef enum
typedef struct
{
+ GVfsBackendAfp *backend;
+
AfpHandleType type;
gint16 fork_refnum;
gint64 offset;
@@ -202,11 +131,12 @@ typedef struct
} AfpHandle;
static AfpHandle *
-afp_handle_new (gint16 fork_refnum)
+afp_handle_new (GVfsBackendAfp *backend, gint16 fork_refnum)
{
AfpHandle *afp_handle;
afp_handle = g_slice_new0 (AfpHandle);
+ afp_handle->backend = backend;
afp_handle->fork_refnum = fork_refnum;
return afp_handle;
@@ -221,1441 +151,6 @@ afp_handle_free (AfpHandle *afp_handle)
g_slice_free (AfpHandle, afp_handle);
}
-static void
-set_access_attributes_trusted (GFileInfo *info,
- guint32 perm)
-{
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
- perm & 0x4);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
- perm & 0x2);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
- perm & 0x1);
-}
-
-/* For files we don't own we can't trust a negative response to this check, as
- something else could allow us to do the operation, for instance an ACL
- or some sticky bit thing */
-static void
-set_access_attributes (GFileInfo *info,
- guint32 perm)
-{
- if (perm & 0x4)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
- TRUE);
- if (perm & 0x2)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
- TRUE);
- if (perm & 0x1)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
- TRUE);
-}
-
-static void fill_info (GVfsBackendAfp *afp_backend,
- GFileInfo *info, GVfsAfpReply *reply,
- gboolean directory, guint16 bitmap)
-{
- goffset start_pos;
-
- if (directory)
- {
- GIcon *icon;
-
- g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
- g_file_info_set_content_type (info, "inode/directory");
-
- icon = g_themed_icon_new ("folder");
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
- }
- else
- g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
-
-
- start_pos = g_vfs_afp_reply_get_pos (reply);
-
- if (bitmap & AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT)
- {
- guint16 attributes;
-
- g_vfs_afp_reply_read_uint16 (reply, &attributes);
-
- if (attributes & AFP_FILEDIR_ATTRIBUTES_BITMAP_INVISIBLE_BIT)
- g_file_info_set_is_hidden (info, TRUE);
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT)
- {
- guint32 parent_dir_id;
-
- g_vfs_afp_reply_read_uint32 (reply, &parent_dir_id);
- g_file_info_set_attribute_uint32 (info, "afp::parent-dir-id", parent_dir_id);
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_CREATE_DATE_BIT)
- {
- gint32 create_date;
- gint64 create_date_local;
-
- g_vfs_afp_reply_read_int32 (reply, &create_date);
-
- create_date_local = g_vfs_afp_server_time_to_local_time (afp_backend->server,
- create_date);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED,
- create_date_local);
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_MOD_DATE_BIT)
- {
- gint32 mod_date;
- guint64 mod_date_unix;
- char *etag;
-
- g_vfs_afp_reply_read_int32 (reply, &mod_date);
- mod_date_unix = g_vfs_afp_server_time_to_local_time (afp_backend->server,
- mod_date);
-
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED,
- mod_date_unix);
-
- etag = g_strdup_printf ("%"G_GUINT64_FORMAT, mod_date_unix);
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag);
- g_free (etag);
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_NODE_ID_BIT)
- {
- guint32 node_id;
-
- g_vfs_afp_reply_read_uint32 (reply, &node_id);
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID, node_id);
- }
-
- /* Directory specific attributes */
- if (directory)
- {
- if (bitmap & AFP_DIR_BITMAP_OFFSPRING_COUNT_BIT)
- {
- guint16 offspring_count;
-
- g_vfs_afp_reply_read_uint16 (reply, &offspring_count);
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_CHILDREN_COUNT,
- offspring_count);
- }
- }
-
- /* File specific attributes */
- else
- {
- if (bitmap & AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT)
- {
- guint64 fork_len;
-
- g_vfs_afp_reply_read_uint64 (reply, &fork_len);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE,
- fork_len);
- }
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_UTF8_NAME_BIT)
- {
- guint16 UTF8Name_offset;
- goffset old_pos;
- GVfsAfpName *afp_name;
- char *utf8_name;
-
- g_vfs_afp_reply_read_uint16 (reply, &UTF8Name_offset);
- /* Pad */
- g_vfs_afp_reply_read_uint32 (reply, NULL);
-
- old_pos = g_vfs_afp_reply_get_pos (reply);
- g_vfs_afp_reply_seek (reply, start_pos + UTF8Name_offset, G_SEEK_SET);
-
- g_vfs_afp_reply_read_afp_name (reply, TRUE, &afp_name);
- utf8_name = g_vfs_afp_name_get_string (afp_name);
- g_vfs_afp_name_unref (afp_name);
-
- g_file_info_set_name (info, utf8_name);
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
- utf8_name);
-
- /* Set file as hidden if it begins with a dot */
- if (utf8_name[0] == '.')
- g_file_info_set_is_hidden (info, TRUE);
-
- if (!directory)
- {
- char *content_type;
- GIcon *icon;
-
- content_type = g_content_type_guess (utf8_name, NULL, 0, NULL);
- g_file_info_set_content_type (info, content_type);
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
- content_type);
-
- icon = g_content_type_get_icon (content_type);
- g_file_info_set_icon (info, icon);
-
- g_object_unref (icon);
- g_free (content_type);
- }
-
- g_free (utf8_name);
-
- g_vfs_afp_reply_seek (reply, old_pos, G_SEEK_SET);
- }
-
- if (bitmap & AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT)
- {
- guint32 uid, gid, permissions, ua_permissions;
-
- g_vfs_afp_reply_read_uint32 (reply, &uid);
- g_vfs_afp_reply_read_uint32 (reply, &gid);
- g_vfs_afp_reply_read_uint32 (reply, &permissions);
- /* ua_permissions */
- g_vfs_afp_reply_read_uint32 (reply, &ua_permissions);
-
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, permissions);
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, uid);
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, gid);
-
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_UA_PERMISSIONS,
- ua_permissions);
-
- if (uid == afp_backend->user_id)
- set_access_attributes_trusted (info, (permissions >> 6) & 0x7);
- else if (gid == afp_backend->group_id)
- set_access_attributes (info, (permissions >> 3) & 0x7);
- else
- set_access_attributes (info, (permissions >> 0) & 0x7);
- }
-}
-
-typedef struct
-{
- gint16 fork_refnum;
- GFileInfo *info;
-} OpenForkData;
-
-static void
-open_fork_data_free (OpenForkData *data)
-{
- g_object_unref (data->info);
-
- g_slice_free (OpenForkData, data);
-}
-
-static void
-open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsBackendAfp *afp_backend;
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- OpenForkData *data;
- guint16 file_bitmap;
-
- afp_backend = G_VFS_BACKEND_AFP (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
-
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
- break;
- case AFP_RESULT_OBJECT_TYPE_ERR:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("File is directory"));
- break;
- case AFP_RESULT_TOO_MANY_FILES_OPEN:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_TOO_MANY_OPEN_FILES,
- _("Too many files open"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- goto done;
- }
-
- data = g_slice_new (OpenForkData);
-
- g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
- g_vfs_afp_reply_read_int16 (reply, &data->fork_refnum);
-
- data->info = g_file_info_new ();
- fill_info (afp_backend, data->info, reply, FALSE, file_bitmap);
- g_object_unref (reply);
-
- g_simple_async_result_set_op_res_gpointer (simple, data,
- (GDestroyNotify)open_fork_data_free);
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-open_fork (GVfsBackendAfp *afp_backend,
- const char *filename,
- guint16 access_mode,
- guint16 bitmap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- if (is_root (filename))
- {
- g_simple_async_report_error_in_idle (G_OBJECT (afp_backend), callback,
- user_data, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("File is directory"));
- return;
- }
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_FORK);
- /* data fork */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* Bitmap */
- g_vfs_afp_command_put_uint16 (comm, bitmap);
-
- /* AccessMode */
- g_vfs_afp_command_put_uint16 (comm, access_mode);
-
- /* Pathname */
- put_pathname (comm, filename);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, open_fork);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- open_fork_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static gboolean
-open_fork_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *res,
- gint16 *fork_refnum,
- GFileInfo **info,
- GError **error)
-{
- GSimpleAsyncResult *simple;
- OpenForkData *data;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (res,
- G_OBJECT (afp_backend),
- open_fork),
- FALSE);
-
- simple = (GSimpleAsyncResult *)res;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- data = g_simple_async_result_get_op_res_gpointer (simple);
- if (fork_refnum)
- *fork_refnum = data->fork_refnum;
- if (info)
- *info = g_object_ref (data->info);
-
- return TRUE;
-}
-
-static void
-close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-close_fork (GVfsBackendAfp *afp_backend,
- gint16 fork_refnum,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_CLOSE_FORK);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* OForkRefNum */
- g_vfs_afp_command_put_int16 (comm, fork_refnum);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback, user_data,
- close_fork);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- close_fork_cb, cancellable,
- simple);
- g_object_unref (comm);
-}
-
-static gboolean
-close_fork_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (afp_backend),
- close_fork),
- FALSE);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- guint16 file_bitmap;
- GFileInfo *info;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
-
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- goto done;
- }
-
- g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
-
- info = g_file_info_new ();
- fill_info (afp_backend, info, reply, FALSE, file_bitmap);
-
- g_object_unref (reply);
-
- g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-get_fork_parms (GVfsBackendAfp *afp_backend,
- gint16 fork_refnum,
- guint16 file_bitmap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FORK_PARMS);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* OForkRefNum */
- g_vfs_afp_command_put_int16 (comm, fork_refnum);
- /* Bitmap */
- g_vfs_afp_command_put_uint16 (comm, file_bitmap);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback, user_data,
- get_fork_parms);
-
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- get_fork_parms_cb, cancellable,
- simple);
- g_object_unref (comm);
-}
-
-static GFileInfo *
-get_fork_parms_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (afp_backend),
- get_fork_parms),
- NULL);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
-
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
-}
-
-static void
-get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- guint16 file_bitmap, dir_bitmap, bitmap;
- guint8 FileDir;
- gboolean directory;
- GFileInfo *info;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
-
- switch (res_code)
- {
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- goto done;
- }
-
- g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
- g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
-
- g_vfs_afp_reply_read_byte (reply, &FileDir);
- /* Pad Byte */
- g_vfs_afp_reply_read_byte (reply, NULL);
-
- directory = (FileDir & 0x80);
- bitmap = directory ? dir_bitmap : file_bitmap;
-
- info = g_file_info_new ();
- fill_info (afp_backend, info, reply, directory, bitmap);
-
- g_object_unref (reply);
-
- g_simple_async_result_set_op_res_gpointer (simple, info, g_object_unref);
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-get_filedir_parms (GVfsBackendAfp *afp_backend,
- const char *filename,
- guint16 file_bitmap,
- guint16 dir_bitmap,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FILE_DIR_PARMS);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* VolumeID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
- /* FileBitmap */
- g_vfs_afp_command_put_uint16 (comm, file_bitmap);
- /* DirectoryBitmap */
- g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
- /* PathName */
- put_pathname (comm, filename);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback, user_data,
- get_filedir_parms);
-
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- get_filedir_parms_cb, cancellable,
- simple);
- g_object_unref (comm);
-}
-
-static GFileInfo *
-get_filedir_parms_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (afp_backend),
- get_filedir_parms),
- NULL);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
-
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
-}
-
-typedef struct
-{
- char *filename;
- gboolean hard_create;
- GCancellable *cancellable;
-} CreateFileData;
-
-static void
-free_create_file_data (CreateFileData *cfd)
-{
- g_free (cfd->filename);
- if (cfd->cancellable)
- g_object_unref (cfd->cancellable);
-
- g_slice_free (CreateFileData, cfd);
-}
-
-static void
-create_file_cb (GObject *object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_DISK_FULL:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
- _("Not enough space on volume"));
- break;
- case AFP_RESULT_FILE_BUSY:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target file is open"));
- break;
- case AFP_RESULT_OBJECT_EXISTS:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target file already exists"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Ancestor directory doesn't exist"));
- break;
- case AFP_RESULT_VOL_LOCKED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Volume is read-only"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- }
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-create_file_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- CreateFileData *cfd = g_simple_async_result_get_op_res_gpointer (simple);
-
- GFileInfo *info;
- GError *err = NULL;
-
- guint32 dir_id;
- char *basename;
- GVfsAfpCommand *comm;
-
- info = get_filedir_parms_finish (afp_backend, res, &err);
- if (!info)
- {
- g_simple_async_result_take_error (simple, err);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
- return;
- }
-
- dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
- g_object_unref (info);
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_FILE);
- /* soft/hard create */
- g_vfs_afp_command_put_byte (comm, cfd->hard_create ? 0x80 : 0x00);
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID */
- g_vfs_afp_command_put_uint32 (comm, dir_id);
-
- /* Pathname */
- basename = g_path_get_basename (cfd->filename);
- put_pathname (comm, basename);
- g_free (basename);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- create_file_cb, cfd->cancellable, simple);
- g_object_unref (comm);
-}
-
-static void
-create_file (GVfsBackendAfp *afp_backend,
- const char *filename,
- gboolean hard_create,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- CreateFileData *cfd;
- GSimpleAsyncResult *simple;
- char *dirname;
-
- cfd = g_slice_new0 (CreateFileData);
- cfd->filename = g_strdup (filename);
- cfd->hard_create = hard_create;
- if (cancellable)
- cfd->cancellable = g_object_ref (cancellable);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback, user_data,
- create_file);
- g_simple_async_result_set_op_res_gpointer (simple, cfd,
- (GDestroyNotify)free_create_file_data);
-
- dirname = g_path_get_dirname (filename);
- get_filedir_parms (afp_backend, dirname, 0, AFP_DIR_BITMAP_NODE_ID_BIT,
- cancellable, create_file_get_filedir_parms_cb, simple);
- g_free (dirname);
-}
-
-static gboolean
-create_file_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (afp_backend),
- create_file),
- FALSE);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_FILE_BUSY:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_BUSY,
- _("Target file is open"));
- break;
- case AFP_RESULT_DIR_NOT_EMPTY:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY,
- _("Directory not empty"));
- break;
- case AFP_RESULT_OBJECT_LOCKED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Target object is marked as not deletable (DeleteInhibit)"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Target object doesn't exist"));
- break;
- case AFP_RESULT_VOL_LOCKED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Volume is read-only"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- }
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-delete (GVfsBackendAfp *afp_backend,
- const char *filename,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_DELETE);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* Pathname */
- put_pathname (comm, filename);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, delete);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- delete_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static gboolean
-delete_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (afp_backend),
- delete),
- FALSE);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-typedef struct
-{
- AfpMapIDFunction function;
- char *name;
-} MapIDData;
-
-static void
-map_id_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
-
- AfpResultCode res_code;
- MapIDData *map_data;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- g_simple_async_result_complete (simple);
- return;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ITEM_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("ID not found"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
-
- g_simple_async_result_complete (simple);
- return;
- }
-
- map_data = g_simple_async_result_get_op_res_gpointer (simple);
-
- if (map_data->function == AFP_MAP_ID_FUNCTION_USER_UUID_TO_UTF8_NAME ||
- map_data->function == AFP_MAP_ID_FUNCTION_GROUP_UUID_TO_UTF8_NAME)
- {
- /* objType */
- g_vfs_afp_reply_read_uint32 (reply, NULL);
- /* id */
- g_vfs_afp_reply_read_uint32 (reply, NULL);
- }
-
- if (map_data->function == AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME ||
- map_data->function == AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME)
- {
- g_vfs_afp_reply_read_pascal (reply, &map_data->name);
- }
- else
- {
- GVfsAfpName *afp_name;
-
- g_vfs_afp_reply_read_afp_name (reply, FALSE, &afp_name);
- map_data->name = g_vfs_afp_name_get_string (afp_name);
- g_vfs_afp_name_unref (afp_name);
- }
-
- g_simple_async_result_complete (simple);
-}
-
-static void
-map_id (GVfsBackendAfp *afp_backend,
- AfpMapIDFunction map_function,
- gint64 id,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
- MapIDData *map_data;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_MAP_ID);
-
- /* SubFunction*/
- g_vfs_afp_command_put_byte (comm, map_function);
-
- /* ID */
- if (map_function == AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME ||
- map_function == AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME)
- g_vfs_afp_command_put_int32 (comm, id);
- else
- g_vfs_afp_command_put_int64 (comm, id);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, map_id);
-
- map_data = g_new (MapIDData, 1);
- map_data->function = map_function;
- g_simple_async_result_set_op_res_gpointer (simple, map_data, g_free);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- map_id_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static char *
-map_id_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *res,
- AfpMapIDFunction *map_function,
- GError **error)
-{
- GSimpleAsyncResult *simple;
- MapIDData *map_data;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (afp_backend),
- map_id),
- NULL);
-
- simple = (GSimpleAsyncResult *)res;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
-
- map_data = g_simple_async_result_get_op_res_gpointer (simple);
-
- if (map_function)
- *map_function = map_data->function;
-
- return map_data->name;
-}
-
-static void
-move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
-
- AfpResultCode res_code;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_CANT_MOVE:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
- _("Can't move directory into one of its descendants"));
- break;
- case AFP_RESULT_INSIDE_SHARE_ERR:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Can't move sharepoint into a shared directory"));
- break;
- case AFP_RESULT_INSIDE_TRASH_ERR:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Can't move a shared directory into the Trash"));
- break;
- case AFP_RESULT_OBJECT_EXISTS:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target file already exists"));
- break;
- case AFP_RESULT_OBJECT_LOCKED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Object being moved is marked as not renameable (RenameInhibit)"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Object being moved doesn't exist"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- }
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-move_and_rename (GVfsBackendAfp *afp_backend,
- const char *source,
- const char *destination,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- char *dirname, *basename;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_MOVE_AND_RENAME);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* VolumeID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
-
- /* SourceDirectoryID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
- /* DestDirectoryID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* SourcePathname */
- put_pathname (comm, source);
-
- /* DestPathname */
- dirname = g_path_get_dirname (destination);
- put_pathname (comm, dirname);
- g_free (dirname);
-
- /* NewName */
- basename = g_path_get_basename (destination);
- put_pathname (comm, basename);
- g_free (basename);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, move_and_rename);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- move_and_rename_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static gboolean
-move_and_rename_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *res,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (afp_backend),
- move_and_rename),
- FALSE);
-
- simple = (GSimpleAsyncResult *)res;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-copy_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
-
- AfpResultCode res_code;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_CALL_NOT_SUPPORTED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Server doesn't support the FPCopyFile operation"));
- break;
- case AFP_RESULT_DENY_CONFLICT:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to open source file for reading"));
- break;
- case AFP_RESULT_DISK_FULL:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
- _("Not enough space on volume"));
- break;
- case AFP_RESULT_OBJECT_EXISTS:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target file already exists"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Source file and/or destination directory doesn't exist"));
- break;
- case AFP_RESULT_OBJECT_TYPE_ERR:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("Source file is a directory"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- }
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-copy_file (GVfsBackendAfp *afp_backend,
- const char *source,
- const char *destination,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- char *dirname, *basename;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_COPY_FILE);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* SourceVolumeID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* SourceDirectoryID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* DestVolumeID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* DestDirectoryID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* SourcePathname */
- put_pathname (comm, source);
-
- /* DestPathname */
- dirname = g_path_get_dirname (destination);
- put_pathname (comm, dirname);
- g_free (dirname);
-
- /* NewName */
- basename = g_path_get_basename (destination);
- put_pathname (comm, basename);
- g_free (basename);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, copy_file);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- copy_file_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static gboolean
-copy_file_finish (GVfsBackendAfp *afp_backend, GAsyncResult *res, GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (afp_backend),
- copy_file),
- FALSE);
-
- simple = (GSimpleAsyncResult *)res;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-set_unix_privs_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- GVfsAfpReply *reply;
- GError *err = NULL;
- AfpResultCode res_code;
-
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
- {
- g_simple_async_result_take_error (simple, err);
- goto done;
- }
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Target object doesn't exist"));
- break;
- case AFP_RESULT_VOL_LOCKED:
- g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Volume is read-only"));
- break;
- default:
- g_simple_async_result_take_error (simple, afp_result_code_to_gerror (res_code));
- break;
- }
- goto done;
- }
-
-done:
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-set_unix_privs (GVfsBackendAfp *afp_backend,
- const char *filename,
- guint32 uid,
- guint32 gid,
- guint32 permissions,
- guint32 ua_permissions,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GVfsAfpCommand *comm;
- GSimpleAsyncResult *simple;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FILEDIR_PARMS);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* VolumeID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* DirectoryID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
- /* Bitmap */
- g_vfs_afp_command_put_uint16 (comm, AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT);
- /* Pathname */
- put_pathname (comm, filename);
- /* pad to even */
- g_vfs_afp_command_pad_to_even (comm);
-
- /* UID */
- g_vfs_afp_command_put_uint32 (comm, uid);
- /* GID */
- g_vfs_afp_command_put_uint32 (comm, gid);
- /* Permissions */
- g_vfs_afp_command_put_uint32 (comm, permissions);
- /* UAPermissions */
- g_vfs_afp_command_put_uint32 (comm, ua_permissions);
-
- simple = g_simple_async_result_new (G_OBJECT (afp_backend), callback,
- user_data, set_unix_privs);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- set_unix_privs_cb, cancellable, simple);
- g_object_unref (comm);
-}
-
-static gboolean
-set_unix_privs_finish (GVfsBackendAfp *afp_backend,
- GAsyncResult *res,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (afp_backend),
- set_unix_privs),
- FALSE);
-
- simple = (GSimpleAsyncResult *)res;
-
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
/*
* Backend code
*/
@@ -1679,12 +174,12 @@ copy_data_free (CopyData *copy_data)
static void
copy_copy_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCopy *job = G_VFS_JOB_COPY (user_data);
GError *err = NULL;
- if (!copy_file_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_copy_file_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -1697,20 +192,21 @@ copy_copy_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
static void
copy_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCopy *job = G_VFS_JOB_COPY (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
GError *err = NULL;
- if (!delete_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_delete_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- copy_file (afp_backend, job->source, job->destination,
- G_VFS_JOB (job)->cancellable, copy_copy_file_cb, job);
+ g_vfs_afp_volume_copy_file (afp_backend->volume, job->source, job->destination,
+ G_VFS_JOB (job)->cancellable, copy_copy_file_cb, job);
}
static void
@@ -1726,7 +222,7 @@ do_copy (CopyData *copy_data)
gboolean dest_exists;
gboolean dest_is_dir;
- info = get_filedir_parms_finish (afp_backend, copy_data->source_parms_res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (afp_backend->volume, copy_data->source_parms_res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -1741,7 +237,7 @@ do_copy (CopyData *copy_data)
source_is_dir = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY ? TRUE : FALSE;
g_object_unref (info);
- info = get_filedir_parms_finish (afp_backend, copy_data->dest_parms_res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (afp_backend->volume, copy_data->dest_parms_res, &err);
if (!info)
{
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
@@ -1798,13 +294,13 @@ do_copy (CopyData *copy_data)
if (dest_exists)
{
- delete (afp_backend, job->destination, G_VFS_JOB (job)->cancellable,
- copy_delete_cb, job);
+ g_vfs_afp_volume_delete (afp_backend->volume, job->destination,
+ G_VFS_JOB (job)->cancellable, copy_delete_cb, job);
}
else
{
- copy_file (afp_backend, job->source, job->destination,
- G_VFS_JOB (job)->cancellable, copy_copy_file_cb, job);
+ g_vfs_afp_volume_copy_file (afp_backend->volume, job->source, job->destination,
+ G_VFS_JOB (job)->cancellable, copy_copy_file_cb, job);
}
done:
@@ -1848,15 +344,17 @@ try_copy (GVfsBackend *backend,
copy_data = g_slice_new0 (CopyData);
copy_data->job = job;
- get_filedir_parms (afp_backend, source, AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- G_VFS_JOB (job)->cancellable, copy_get_source_parms_cb,
- copy_data);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, source,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ G_VFS_JOB (job)->cancellable, copy_get_source_parms_cb,
+ copy_data);
- get_filedir_parms (afp_backend, destination, AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- G_VFS_JOB (job)->cancellable, copy_get_dest_parms_cb,
- copy_data);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, destination,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ G_VFS_JOB (job)->cancellable, copy_get_dest_parms_cb,
+ copy_data);
return TRUE;
}
@@ -1864,12 +362,12 @@ try_copy (GVfsBackend *backend,
static void
move_move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobMove *job = G_VFS_JOB_MOVE (user_data);
GError *err = NULL;
- if (!move_and_rename_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_move_and_rename_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -1882,21 +380,21 @@ move_move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer use
static void
move_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobMove *job = G_VFS_JOB_MOVE (user_data);
GError *err = NULL;
- if (!delete_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_delete_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- move_and_rename (afp_backend, job->source, job->destination,
- G_VFS_JOB (job)->cancellable, move_move_and_rename_cb,
- job);
+ g_vfs_afp_volume_move_and_rename (volume, job->source, job->destination,
+ G_VFS_JOB (job)->cancellable, move_move_and_rename_cb,
+ job);
}
typedef struct
@@ -1928,7 +426,8 @@ do_move (MoveData *move_data)
gboolean dest_exists;
gboolean dest_is_dir;
- info = get_filedir_parms_finish (afp_backend, move_data->source_parms_res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (afp_backend->volume,
+ move_data->source_parms_res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -1939,7 +438,8 @@ do_move (MoveData *move_data)
source_is_dir = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY ? TRUE : FALSE;
g_object_unref (info);
- info = get_filedir_parms_finish (afp_backend, move_data->dest_parms_res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (afp_backend->volume,
+ move_data->dest_parms_res, &err);
if (!info)
{
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
@@ -1984,13 +484,13 @@ do_move (MoveData *move_data)
goto done;
}
- delete (afp_backend, job->destination, G_VFS_JOB (job)->cancellable,
- move_delete_cb, job);
+ g_vfs_afp_volume_delete (afp_backend->volume, job->destination,
+ G_VFS_JOB (job)->cancellable, move_delete_cb, job);
}
else
- move_and_rename (afp_backend, job->source, job->destination,
- G_VFS_JOB (job)->cancellable, move_move_and_rename_cb,
- job);
+ g_vfs_afp_volume_move_and_rename (afp_backend->volume, job->source, job->destination,
+ G_VFS_JOB (job)->cancellable, move_move_and_rename_cb,
+ job);
done:
free_move_data (move_data);
@@ -2033,15 +533,17 @@ try_move (GVfsBackend *backend,
move_data = g_slice_new0 (MoveData);
move_data->job = job;
- get_filedir_parms (afp_backend, source, AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- G_VFS_JOB (job)->cancellable, move_get_source_parms_cb,
- move_data);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, source,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ G_VFS_JOB (job)->cancellable, move_get_source_parms_cb,
+ move_data);
- get_filedir_parms (afp_backend, destination, AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
- G_VFS_JOB (job)->cancellable, move_get_dest_parms_cb,
- move_data);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, destination,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ AFP_FILEDIR_BITMAP_ATTRIBUTE_BIT,
+ G_VFS_JOB (job)->cancellable, move_get_dest_parms_cb,
+ move_data);
return TRUE;
}
@@ -2049,60 +551,19 @@ try_move (GVfsBackend *backend,
static void
rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobSetDisplayName *job = G_VFS_JOB_SET_DISPLAY_NAME (user_data);
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
char *dirname, *newpath;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_rename_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_CANT_RENAME:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
- _("Can't rename volume"));
- break;
- case AFP_RESULT_OBJECT_EXISTS:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Object with that name already exists"));
- break;
- case AFP_RESULT_OBJECT_LOCKED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Target object is marked as not renameable (RenameInhibit)"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Target object doesn't exist"));
- break;
- case AFP_RESULT_VOL_LOCKED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Volume is read-only"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
- return;
- }
-
dirname = g_path_get_dirname (job->filename);
newpath = g_build_filename (dirname, job->display_name, NULL);
g_vfs_job_set_display_name_set_new_path (job, newpath);
@@ -2112,53 +573,6 @@ rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
g_vfs_job_succeeded (G_VFS_JOB (job));
}
-
-static void
-set_display_name_get_filedir_parms_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
- GVfsJobSetDisplayName *job = G_VFS_JOB_SET_DISPLAY_NAME (user_data);
-
- GFileInfo *info;
- GError *err = NULL;
-
- guint32 dir_id;
- GVfsAfpCommand *comm;
- char *basename;
-
- info = get_filedir_parms_finish (afp_backend, res, &err);
- if (!info)
- {
- g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
- g_error_free (err);
- return;
- }
-
- dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_PARENT_DIR_ID);
- g_object_unref (info);
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_RENAME);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID */
- g_vfs_afp_command_put_uint32 (comm, dir_id);
-
- /* Pathname */
- basename = g_path_get_basename (job->filename);
- put_pathname (comm, basename);
- g_free (basename);
-
- /* NewName */
- put_pathname (comm, job->display_name);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- rename_cb, G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
-}
static gboolean
try_set_display_name (GVfsBackend *backend,
@@ -2175,115 +589,29 @@ try_set_display_name (GVfsBackend *backend,
return TRUE;
}
- get_filedir_parms (afp_backend, filename, AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
- AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
- G_VFS_JOB (job)->cancellable,
- set_display_name_get_filedir_parms_cb, job);
+ g_vfs_afp_volume_rename (afp_backend->volume, filename, display_name,
+ G_VFS_JOB (job)->cancellable, rename_cb, job);
return TRUE;
}
static void
-make_directory_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+create_directory_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobMakeDirectory *job = G_VFS_JOB_MAKE_DIRECTORY (user_data);
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_create_directory_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_DISK_FULL:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NO_SPACE,
- _("Not enough space on volume"));
- break;
- case AFP_RESULT_FLAT_VOL:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Volume is flat and doesn't support directories"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Ancestor directory doesn't exist"));
- break;
- case AFP_RESULT_OBJECT_EXISTS:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS,
- _("Target directory already exists"));
- break;
- case AFP_RESULT_VOL_LOCKED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Volume is read-only"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
- return;
- }
-
g_vfs_job_succeeded (G_VFS_JOB (job));
}
-static void
-make_directory_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
- GVfsJobMakeDirectory *job = G_VFS_JOB_MAKE_DIRECTORY (user_data);
-
- GFileInfo *info;
- GError *err = NULL;
-
- guint32 dir_id;
- char *basename;
- GVfsAfpCommand *comm;
-
- info = get_filedir_parms_finish (afp_backend, res, &err);
- if (!info)
- {
- g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
- g_error_free (err);
- return;
- }
-
- dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
- g_object_unref (info);
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_DIR);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID */
- g_vfs_afp_command_put_uint32 (comm, dir_id);
-
- /* Pathname */
- basename = g_path_get_basename (job->filename);
- put_pathname (comm, basename);
- g_free (basename);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- make_directory_cb,
- G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
-}
-
static gboolean
try_make_directory (GVfsBackend *backend,
GVfsJobMakeDirectory *job,
@@ -2291,26 +619,21 @@ try_make_directory (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- char *dirname;
-
- dirname = g_path_get_dirname (filename);
- get_filedir_parms (afp_backend, dirname, 0, AFP_DIR_BITMAP_NODE_ID_BIT,
- G_VFS_JOB (job)->cancellable, make_directory_get_filedir_parms_cb,
- job);
- g_free (dirname);
-
+ g_vfs_afp_volume_create_directory (afp_backend->volume, job->filename,
+ G_VFS_JOB (job)->cancellable,
+ create_directory_cb, job);
return TRUE;
}
static void
delete_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobDelete *job = G_VFS_JOB_DELETE (user_data);
GError *err = NULL;
- if (!delete_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_delete_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -2327,58 +650,30 @@ try_delete (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- delete (afp_backend, filename, G_VFS_JOB (job)->cancellable,
- delete_delete_cb, job);
+ g_vfs_afp_volume_delete (afp_backend->volume, filename,
+ G_VFS_JOB (job)->cancellable, delete_delete_cb, job);
return TRUE;
}
static void
-write_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobWrite *job = G_VFS_JOB_WRITE (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
gint64 last_written;
gsize written_size;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_write_to_fork_finish (volume, res, &last_written, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (!(res_code == AFP_RESULT_NO_ERROR || res_code == AFP_RESULT_LOCK_ERR))
- {
- g_object_unref (reply);
-
- switch (res_code)
- {
- case 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 write access"));
- break;
- case AFP_RESULT_DISK_FULL:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NO_SPACE,
- _("Not enough space on volume"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
- return;
- }
-
- g_vfs_afp_reply_read_int64 (reply, &last_written);
- g_object_unref (reply);
-
written_size = last_written - afp_handle->offset;
afp_handle->offset = last_written;
@@ -2399,27 +694,9 @@ try_write (GVfsBackend *backend,
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_WRITE_EXT);
- /* StartEndFlag = 0 */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* OForkRefNum */
- g_vfs_afp_command_put_int16 (comm, afp_handle->fork_refnum);
- /* Offset */
- g_vfs_afp_command_put_int64 (comm, afp_handle->offset);
- /* ReqCount */
- req_count = MIN (buffer_size, G_MAXUINT32);
- g_vfs_afp_command_put_int64 (comm, req_count);
-
- g_vfs_afp_command_set_buffer (comm, buffer, buffer_size);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- write_ext_cb, G_VFS_JOB (job)->cancellable,
- job);
- g_object_unref (comm);
+ g_vfs_afp_volume_write_to_fork (afp_backend->volume, afp_handle->fork_refnum,
+ buffer, buffer_size, afp_handle->offset,
+ G_VFS_JOB (job)->cancellable, write_cb, job);
return TRUE;
}
@@ -2427,7 +704,7 @@ try_write (GVfsBackend *backend,
static void
seek_on_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobSeekWrite *job = G_VFS_JOB_SEEK_WRITE (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
@@ -2435,7 +712,7 @@ seek_on_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
GFileInfo *info;
gsize size;
- info = get_fork_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_fork_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -2504,9 +781,9 @@ try_seek_on_write (GVfsBackend *backend,
else
{
- get_fork_parms (afp_backend, afp_handle->fork_refnum,
- AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
- G_VFS_JOB (job)->cancellable, seek_on_write_cb, job);
+ g_vfs_afp_volume_get_fork_parms (afp_backend->volume, afp_handle->fork_refnum,
+ AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
+ G_VFS_JOB (job)->cancellable, seek_on_write_cb, job);
}
return TRUE;
@@ -2515,7 +792,7 @@ try_seek_on_write (GVfsBackend *backend,
static void
seek_on_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobSeekRead *job = G_VFS_JOB_SEEK_READ (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
@@ -2523,7 +800,7 @@ seek_on_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
GFileInfo *info;
gsize size;
- info = get_fork_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_fork_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -2566,59 +843,32 @@ try_seek_on_read (GVfsBackend *backend,
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
AfpHandle *afp_handle = (AfpHandle *)handle;
- get_fork_parms (afp_backend, afp_handle->fork_refnum,
- AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
- G_VFS_JOB (job)->cancellable, seek_on_read_cb, job);
+ g_vfs_afp_volume_get_fork_parms (afp_backend->volume, afp_handle->fork_refnum,
+ AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
+ G_VFS_JOB (job)->cancellable, seek_on_read_cb, job);
return TRUE;
}
static void
-read_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobRead *job = G_VFS_JOB_READ (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
- gsize size;
+ gsize bytes_read;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_read_from_fork_finish (volume, res, &bytes_read, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
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);
-
- switch (res_code)
- {
- case 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"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
-
- return;
- }
-
- size = g_vfs_afp_reply_get_size (reply);
-
- afp_handle->offset += size;
- g_vfs_job_read_set_size (job, size);
-
- g_object_unref (reply);
+ afp_handle->offset += bytes_read;
+ g_vfs_job_read_set_size (job, bytes_read);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
@@ -2632,40 +882,23 @@ try_read (GVfsBackend *backend,
{
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_vfs_afp_command_put_byte (comm, 0);
-
- /* OForkRefNum */
- g_vfs_afp_command_put_int16 (comm, afp_handle->fork_refnum);
- /* Offset */
- g_vfs_afp_command_put_int64 (comm, afp_handle->offset);
- /* ReqCount */
- req_count = MIN (bytes_requested, G_MAXUINT32);
- g_vfs_afp_command_put_int64 (comm, req_count);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, buffer,
- read_ext_cb, G_VFS_JOB (job)->cancellable,
- job);
- g_object_unref (comm);
+ g_vfs_afp_volume_read_from_fork (afp_backend->volume, afp_handle->fork_refnum,
+ buffer, bytes_requested, afp_handle->offset,
+ G_VFS_JOB (job)->cancellable, read_cb, job);
return TRUE;
}
static void
close_replace_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCloseWrite *job = G_VFS_JOB_CLOSE_WRITE (user_data);
GFileInfo *info;
GError *err = NULL;
- info = get_filedir_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -2682,23 +915,23 @@ close_replace_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, g
static void
close_replace_delete_backup_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
AfpHandle *afp_handle = (AfpHandle *)user_data;
char *backup_name;
/* We ignore all errors and just try to rename the temporary file anyway */
backup_name = g_strconcat (afp_handle->filename, "~", NULL);
-
- move_and_rename (afp_backend, afp_handle->tmp_filename, backup_name, NULL,
- NULL, NULL);
+
+ g_vfs_afp_volume_move_and_rename (volume, afp_handle->tmp_filename, backup_name,
+ NULL, NULL, NULL);
afp_handle_free (afp_handle);
}
static void
close_replace_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
AfpHandle *afp_handle = (AfpHandle *)user_data;
if (afp_handle->make_backup)
@@ -2706,15 +939,15 @@ close_replace_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer
char *backup_name = g_strconcat (afp_handle->filename, "~", NULL);
/* Delete old backup */
- delete (afp_backend, backup_name, NULL, close_replace_delete_backup_cb,
- afp_handle);
+ g_vfs_afp_volume_delete (volume, backup_name, NULL,
+ close_replace_delete_backup_cb, afp_handle);
g_free (backup_name);
}
else
{
/* Delete temporary file */
- delete (afp_backend, afp_handle->tmp_filename, NULL, NULL, NULL);
+ g_vfs_afp_volume_delete (volume, afp_handle->tmp_filename, NULL, NULL, NULL);
afp_handle_free (afp_handle);
}
@@ -2723,17 +956,13 @@ close_replace_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer
static void
close_replace_exchange_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCloseWrite *job = G_VFS_JOB_CLOSE_WRITE (user_data);
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_exchange_files_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -2742,51 +971,26 @@ close_replace_exchange_files_cb (GObject *source_object, GAsyncResult *res, gpoi
}
/* Close fork and remove/rename the temporary file even if the exchange failed */
- close_fork (afp_backend, afp_handle->fork_refnum, G_VFS_JOB (job)->cancellable,
- close_replace_close_fork_cb, job->handle);
+ g_vfs_afp_volume_close_fork (volume, afp_handle->fork_refnum,
+ G_VFS_JOB (job)->cancellable,
+ close_replace_close_fork_cb, job->handle);
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
-
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Permission denied"));
- break;
- case AFP_RESULT_ID_NOT_FOUND:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
- break;
- case AFP_RESULT_OBJECT_TYPE_ERR:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("File is directory"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
- return;
- }
-
/* Get ETAG */
- get_filedir_parms (afp_backend, afp_handle->filename,
- AFP_FILE_BITMAP_MOD_DATE_BIT, 0,
- G_VFS_JOB (job)->cancellable,
- close_replace_get_filedir_parms_cb, job);
+ g_vfs_afp_volume_get_filedir_parms (volume, afp_handle->filename,
+ AFP_FILE_BITMAP_MOD_DATE_BIT, 0,
+ G_VFS_JOB (job)->cancellable,
+ close_replace_get_filedir_parms_cb, job);
}
static void
-close_write_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
- GVfsJobCloseWrite *job = G_VFS_JOB_CLOSE_WRITE (user_data);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
+ GVfsJob *job = G_VFS_JOB (user_data);
GError *err = NULL;
- if (!close_fork_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_close_fork_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -2797,9 +1001,20 @@ close_write_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer u
}
static void
+close_fork (GVfsAfpVolume *volume,
+ GVfsJob *job,
+ AfpHandle *afp_handle)
+{
+ g_vfs_afp_volume_close_fork (volume, afp_handle->fork_refnum,
+ G_VFS_JOB (job)->cancellable,
+ close_fork_cb, job);
+ afp_handle_free (afp_handle);
+}
+
+static void
close_write_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCloseWrite *job = G_VFS_JOB_CLOSE_WRITE (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
@@ -2807,7 +1022,7 @@ close_write_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpoint
GError *err = NULL;
GFileInfo *info;
- info = get_fork_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_fork_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -2818,26 +1033,20 @@ close_write_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpoint
}
g_vfs_job_close_write_set_etag (job, g_file_info_get_etag (info));
-
- close_fork (afp_backend, afp_handle->fork_refnum, G_VFS_JOB (job)->cancellable,
- close_write_close_fork_cb, job);
- afp_handle_free (afp_handle);
+ close_fork (volume, G_VFS_JOB (job), afp_handle);
}
static void
-close_replace_set_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+close_replace_set_fork_size_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobCloseWrite *job = G_VFS_JOB_CLOSE_WRITE (user_data);
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
AfpHandle *afp_handle = (AfpHandle *)job->handle;
- GVfsAfpReply *reply;
GError *err = NULL;
- AfpResultCode res_code;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+ if (!g_vfs_afp_volume_set_fork_size_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -2845,36 +1054,11 @@ close_replace_set_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpoi
return;
}
- res_code = g_vfs_afp_reply_get_result_code (reply);
- g_object_unref (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Permission denied"));
- break;
- case AFP_RESULT_DISK_FULL:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NO_SPACE,
- _("Not enough space on volume"));
- break;
- case AFP_RESULT_LOCK_ERR:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Range lock conflict exists"));
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
- afp_handle_free (afp_handle);
- return;
- }
-
/* Get ETAG */
- get_fork_parms (afp_backend, afp_handle->fork_refnum, AFP_FILE_BITMAP_MOD_DATE_BIT,
- G_VFS_JOB (job)->cancellable, close_write_get_fork_parms_cb,
- job);
+ g_vfs_afp_volume_get_fork_parms (afp_backend->volume, afp_handle->fork_refnum,
+ AFP_FILE_BITMAP_MOD_DATE_BIT,
+ G_VFS_JOB (job)->cancellable,
+ close_write_get_fork_parms_cb, job);
}
static gboolean
@@ -2887,78 +1071,29 @@ try_close_write (GVfsBackend *backend,
if (afp_handle->type == AFP_HANDLE_TYPE_REPLACE_FILE_TEMP)
{
- GVfsAfpCommand *comm;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_EXCHANGE_FILES);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* SourceDirectory ID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
- /* DestDirectory ID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
-
- /* SourcePath */
- put_pathname (comm, afp_handle->filename);
- /* DestPath */
- put_pathname (comm, afp_handle->tmp_filename);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- close_replace_exchange_files_cb,
- G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
+ g_vfs_afp_volume_exchange_files (afp_backend->volume, afp_handle->filename,
+ afp_handle->tmp_filename,
+ G_VFS_JOB (job)->cancellable,
+ close_replace_exchange_files_cb, job);
}
else if (afp_handle->type == AFP_HANDLE_TYPE_REPLACE_FILE_DIRECT)
{
- GVfsAfpCommand *comm;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FORK_PARMS);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* OForkRefNum */
- g_vfs_afp_command_put_int16 (comm, afp_handle->fork_refnum);
- /* Bitmap */
- g_vfs_afp_command_put_uint16 (comm, AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT);
- /* ForkLen */
- g_vfs_afp_command_put_int64 (comm, afp_handle->size);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, NULL,
- close_replace_set_fork_parms_cb,
- G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
+ g_vfs_afp_volume_set_fork_size (afp_backend->volume, afp_handle->fork_refnum,
+ afp_handle->size, G_VFS_JOB (job)->cancellable,
+ close_replace_set_fork_size_cb, job);
}
else
{
/* Get ETAG */
- get_fork_parms (afp_backend, afp_handle->fork_refnum, AFP_FILE_BITMAP_MOD_DATE_BIT,
- G_VFS_JOB (job)->cancellable, close_write_get_fork_parms_cb,
- job);
+ g_vfs_afp_volume_get_fork_parms (afp_backend->volume, afp_handle->fork_refnum,
+ AFP_FILE_BITMAP_MOD_DATE_BIT,
+ G_VFS_JOB (job)->cancellable,
+ close_write_get_fork_parms_cb, job);
}
return TRUE;
}
-static void
-close_read_close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
- GVfsJobCloseRead *job = G_VFS_JOB_CLOSE_READ (user_data);
-
- GError *err = NULL;
-
- if (!close_fork_finish (afp_backend, res, &err))
- {
- g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
- g_error_free (err);
- return;
- }
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
static gboolean
try_close_read (GVfsBackend *backend,
GVfsJobCloseRead *job,
@@ -2967,9 +1102,7 @@ try_close_read (GVfsBackend *backend,
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
AfpHandle *afp_handle = (AfpHandle *)handle;
- close_fork (afp_backend, afp_handle->fork_refnum, G_VFS_JOB (job)->cancellable,
- close_read_close_fork_cb, job);
- afp_handle_free ((AfpHandle *)job->handle);
+ close_fork (afp_backend->volume, G_VFS_JOB (job), afp_handle);
return TRUE;
}
@@ -2977,21 +1110,22 @@ try_close_read (GVfsBackend *backend,
static void
create_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
gint16 fork_refnum;
GError *err = NULL;
AfpHandle *afp_handle;
- if (!open_fork_finish (afp_backend, res, &fork_refnum, NULL, &err))
+ if (!g_vfs_afp_volume_open_fork_finish (volume, res, &fork_refnum, NULL, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- afp_handle = afp_handle_new (fork_refnum);
+ afp_handle = afp_handle_new (afp_backend, fork_refnum);
afp_handle->type = AFP_HANDLE_TYPE_CREATE_FILE;
g_vfs_job_open_for_write_set_handle (job, (GVfsBackendHandle) afp_handle);
@@ -3004,20 +1138,20 @@ create_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_da
static void
create_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
GError *err = NULL;
- if (!create_file_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_create_file_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- open_fork (afp_backend, job->filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
- G_VFS_JOB (job)->cancellable, create_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (volume, job->filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
+ G_VFS_JOB (job)->cancellable, create_open_fork_cb, job);
}
static gboolean
@@ -3028,8 +1162,8 @@ try_create (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- create_file (afp_backend, filename, FALSE, G_VFS_JOB (job)->cancellable,
- create_cb, job);
+ g_vfs_afp_volume_create_file (afp_backend->volume, filename, FALSE,
+ G_VFS_JOB (job)->cancellable, create_cb, job);
return TRUE;
}
@@ -3037,22 +1171,23 @@ try_create (GVfsBackend *backend,
static void
replace_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
gint16 fork_refnum;
GError *err = NULL;
AfpHandle *afp_handle;
char *tmp_filename;
- if (!open_fork_finish (afp_backend, res, &fork_refnum, NULL, &err))
+ if (!g_vfs_afp_volume_open_fork_finish (volume, res, &fork_refnum, NULL, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- afp_handle = afp_handle_new (fork_refnum);
+ afp_handle = afp_handle_new (afp_backend, fork_refnum);
tmp_filename = g_object_get_data (G_OBJECT (job), "TempFilename");
/* Replace using temporary file */
if (tmp_filename)
@@ -3072,21 +1207,21 @@ replace_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_d
g_vfs_job_succeeded (G_VFS_JOB (job));
}
-static void replace_create_tmp_file (GVfsBackendAfp *afp_backend, GVfsJobOpenForWrite *job);
+static void replace_create_tmp_file (GVfsAfpVolume *volume, GVfsJobOpenForWrite *job);
static void
replace_create_tmp_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
GError *err = NULL;
char *tmp_filename;
- if (!create_file_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_create_file_finish (volume, res, &err))
{
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_EXISTS))
- replace_create_tmp_file (afp_backend, job);
+ replace_create_tmp_file (volume, job);
/* We don't have the necessary permissions to create a temporary file
* so we try to write directly to the file */
@@ -3102,8 +1237,9 @@ replace_create_tmp_file_cb (GObject *source_object, GAsyncResult *res, gpointer
else
{
g_object_set_data (G_OBJECT (job), "TempFilename", NULL);
- open_fork (afp_backend, job->filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
- G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (volume, job->filename,
+ AFP_ACCESS_MODE_WRITE_BIT, 0,
+ G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
}
}
@@ -3117,8 +1253,9 @@ replace_create_tmp_file_cb (GObject *source_object, GAsyncResult *res, gpointer
}
tmp_filename = g_object_get_data (G_OBJECT (job), "TempFilename");
- open_fork (afp_backend, tmp_filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
- G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (volume, tmp_filename,
+ AFP_ACCESS_MODE_WRITE_BIT, 0,
+ G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
}
static void
@@ -3132,7 +1269,7 @@ random_chars (char *str, int len)
}
static void
-replace_create_tmp_file (GVfsBackendAfp *afp_backend, GVfsJobOpenForWrite *job)
+replace_create_tmp_file (GVfsAfpVolume *volume, GVfsJobOpenForWrite *job)
{
char basename[] = "~gvfXXXX.tmp";
char *dir, *tmp_filename;
@@ -3144,20 +1281,22 @@ replace_create_tmp_file (GVfsBackendAfp *afp_backend, GVfsJobOpenForWrite *job)
g_free (dir);
g_object_set_data_full (G_OBJECT (job), "TempFilename", tmp_filename, g_free);
- create_file (afp_backend, tmp_filename, FALSE, G_VFS_JOB (job)->cancellable,
- replace_create_tmp_file_cb, job);
+ g_vfs_afp_volume_create_file (volume, tmp_filename, FALSE,
+ G_VFS_JOB (job)->cancellable,
+ replace_create_tmp_file_cb, job);
}
static void
replace_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
GError *err = NULL;
GFileInfo *info;
- info = get_filedir_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
if (!info)
{
/* Create file if it doesn't exist */
@@ -3185,7 +1324,7 @@ replace_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointe
}
else
{
- if (afp_backend->vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_NO_EXCHANGE_FILES)
+ if (g_vfs_afp_volume_get_attributes (volume) & AFP_VOLUME_ATTRIBUTES_BITMAP_NO_EXCHANGE_FILES)
{
/* FIXME: We don't support making backups when we can't use FPExchangeFiles */
if (job->make_backup)
@@ -3196,12 +1335,13 @@ replace_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointe
}
else
{
- open_fork (afp_backend, job->filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
- G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (volume, job->filename,
+ AFP_ACCESS_MODE_WRITE_BIT, 0,
+ G_VFS_JOB (job)->cancellable, replace_open_fork_cb, job);
}
}
else
- replace_create_tmp_file (afp_backend, job);
+ replace_create_tmp_file (volume, job);
}
g_object_unref (info);
@@ -3217,16 +1357,17 @@ try_replace (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- get_filedir_parms (afp_backend, filename, AFP_FILE_BITMAP_MOD_DATE_BIT, 0,
- G_VFS_JOB (job)->cancellable, replace_get_filedir_parms_cb,
- job);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, filename,
+ AFP_FILE_BITMAP_MOD_DATE_BIT, 0,
+ G_VFS_JOB (job)->cancellable,
+ replace_get_filedir_parms_cb, job);
return TRUE;
}
static void
append_to_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
AfpHandle *afp_handle = (AfpHandle *)job->backend_handle;
@@ -3234,7 +1375,7 @@ append_to_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer
GError *err = NULL;
goffset size;
- info = get_fork_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_fork_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -3256,14 +1397,15 @@ append_to_get_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer
static void
append_to_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForWrite *job = G_VFS_JOB_OPEN_FOR_WRITE (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
gint16 fork_refnum;
GError *err = NULL;
AfpHandle *afp_handle;
- if (!open_fork_finish (afp_backend, res, &fork_refnum, NULL, &err))
+ if (!g_vfs_afp_volume_open_fork_finish (volume, res, &fork_refnum, NULL, &err))
{
/* Create file if it doesn't exist */
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
@@ -3276,14 +1418,14 @@ append_to_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user
return;
}
- afp_handle = afp_handle_new (fork_refnum);
+ afp_handle = afp_handle_new (afp_backend, fork_refnum);
afp_handle->type = AFP_HANDLE_TYPE_APPEND_TO_FILE;
g_vfs_job_open_for_write_set_handle (job, (GVfsBackendHandle) afp_handle);
- get_fork_parms (afp_backend, afp_handle->fork_refnum,
- AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
- G_VFS_JOB (job)->cancellable, append_to_get_fork_parms_cb,
- job);
+ g_vfs_afp_volume_get_fork_parms (afp_backend->volume, afp_handle->fork_refnum,
+ AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT,
+ G_VFS_JOB (job)->cancellable,
+ append_to_get_fork_parms_cb, job);
}
static gboolean
@@ -3294,29 +1436,31 @@ try_append_to (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- open_fork (afp_backend, job->filename, AFP_ACCESS_MODE_WRITE_BIT, 0,
- G_VFS_JOB (job)->cancellable, append_to_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (afp_backend->volume, job->filename,
+ AFP_ACCESS_MODE_WRITE_BIT, 0,
+ G_VFS_JOB (job)->cancellable, append_to_open_fork_cb, job);
return TRUE;
}
static void
read_open_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobOpenForRead *job = G_VFS_JOB_OPEN_FOR_READ (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
GError *err = NULL;
gint16 fork_refnum;
AfpHandle *afp_handle;
- if (!open_fork_finish (afp_backend, res, &fork_refnum, NULL, &err))
+ if (!g_vfs_afp_volume_open_fork_finish (volume, res, &fork_refnum, NULL, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- afp_handle = afp_handle_new (fork_refnum);
+ afp_handle = afp_handle_new (afp_backend, fork_refnum);
afp_handle->type = AFP_HANDLE_TYPE_READ_FILE;
g_vfs_job_open_for_read_set_handle (job, (GVfsBackendHandle) afp_handle);
@@ -3332,8 +1476,9 @@ try_open_for_read (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- open_fork (afp_backend, filename, AFP_ACCESS_MODE_READ_BIT, 0,
- G_VFS_JOB (job)->cancellable, read_open_fork_cb, job);
+ g_vfs_afp_volume_open_fork (afp_backend->volume, filename,
+ AFP_ACCESS_MODE_READ_BIT, 0,
+ G_VFS_JOB (job)->cancellable, read_open_fork_cb, job);
return TRUE;
}
@@ -3362,7 +1507,7 @@ create_filedir_bitmap (GVfsBackendAfp *afp_backend, GFileAttributeMatcher *match
g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_OWNER_GROUP))
{
- if (afp_backend->vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
+ if (g_vfs_afp_volume_get_attributes (afp_backend->volume) & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
bitmap |= AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT;
}
@@ -3403,102 +1548,39 @@ enumerate (GVfsBackendAfp *afp_backend,
static void
enumerate_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobEnumerate *job = G_VFS_JOB_ENUMERATE (user_data);
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
- GVfsAfpReply *reply;
+ GPtrArray *infos;
GError *err = NULL;
- AfpResultCode res_code;
-
- guint16 file_bitmap;
- guint16 dir_bitmap;
- gint16 count, i;
- gint64 start_index, max;
+ guint i;
+ gint64 start_index;
- reply = g_vfs_afp_connection_send_command_finish (afp_conn, res, &err);
- if (!reply)
+
+ if (!g_vfs_afp_volume_enumerate_finish (volume, res, &infos, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
return;
}
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
+ /* No more files */
+ if (!infos)
{
- g_object_unref (reply);
-
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- case AFP_RESULT_DIR_NOT_FOUND:
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("Directory doesn't exist"));
- break;
- case AFP_RESULT_OBJECT_TYPE_ERR:
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
- _("Target object is not a directory"));
- break;
- case AFP_RESULT_OBJECT_NOT_FOUND:
- g_vfs_job_succeeded (G_VFS_JOB (job));
- g_vfs_job_enumerate_done (job);
- break;
- default:
- job_failed_from_afp_result_code (G_VFS_JOB (job), res_code);
- break;
- }
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ g_vfs_job_enumerate_done (job);
return;
}
- g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
- g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
-
- g_vfs_afp_reply_read_int16 (reply, &count);
- for (i = 0; i < count; i++)
- {
- goffset start_pos;
- guint16 struct_length;
- guint8 FileDir;
-
- gboolean directory;
- guint16 bitmap;
- GFileInfo *info;
-
- start_pos = g_vfs_afp_reply_get_pos (reply);
-
- g_vfs_afp_reply_read_uint16 (reply, &struct_length);
- g_vfs_afp_reply_read_byte (reply, &FileDir);
- /* pad byte */
- g_vfs_afp_reply_read_byte (reply, NULL);
-
- directory = (FileDir & 0x80);
- bitmap = directory ? dir_bitmap : file_bitmap;
-
- info = g_file_info_new ();
- fill_info (afp_backend, info, reply, directory, bitmap);
- g_vfs_job_enumerate_add_info (job, info);
- g_object_unref (info);
-
- g_vfs_afp_reply_seek (reply, start_pos + struct_length, G_SEEK_SET);
- }
- g_object_unref (reply);
+ for (i = 0; i < infos->len; i++)
+ g_vfs_job_enumerate_add_info (job, g_ptr_array_index (infos, i));
start_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (job),
"start-index"));
- start_index += count;
-
- max = (afp_backend->server->version >= AFP_VERSION_3_1) ? G_MAXINT32 : G_MAXINT16;
- /* Can't enumerate any more files */
- if (start_index > max)
- {
- g_vfs_job_succeeded (G_VFS_JOB (job));
- g_vfs_job_enumerate_done (job);
- }
+ start_index += infos->len;
+ g_ptr_array_unref (infos);
enumerate (afp_backend, job, start_index);
}
@@ -3508,59 +1590,20 @@ enumerate (GVfsBackendAfp *afp_backend,
GVfsJobEnumerate *job,
gint32 start_index)
{
- GVfsAfpConnection *conn = afp_backend->server->conn;
const char *filename = job->filename;
GFileAttributeMatcher *matcher = job->attribute_matcher;
- GVfsAfpCommand *comm;
guint16 file_bitmap, dir_bitmap;
-
- if (afp_backend->server->version >= AFP_VERSION_3_1)
- comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT2);
- else
- comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
-
- /* Volume ID */
- g_vfs_afp_command_put_uint16 (comm, afp_backend->volume_id);
- /* Directory ID 2 == / */
- g_vfs_afp_command_put_uint32 (comm, 2);
+ g_object_set_data (G_OBJECT (job), "start-index",
+ GINT_TO_POINTER (start_index));
- /* File Bitmap */
file_bitmap = create_file_bitmap (afp_backend, matcher);
- g_vfs_afp_command_put_uint16 (comm, file_bitmap);
-
- /* Dir Bitmap */
dir_bitmap = create_dir_bitmap (afp_backend, matcher);
- g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
-
- /* Req Count */
- g_vfs_afp_command_put_int16 (comm, ENUMERATE_REQ_COUNT);
-
-
- /* StartIndex and MaxReplySize */
- if (afp_backend->server->version >= AFP_VERSION_3_1)
- {
- g_vfs_afp_command_put_int32 (comm, start_index);
- g_vfs_afp_command_put_int32 (comm, ENUMERATE_EXT2_MAX_REPLY_SIZE);
- }
- else
- {
- g_vfs_afp_command_put_int16 (comm, start_index);
- g_vfs_afp_command_put_int16 (comm, ENUMERATE_EXT_MAX_REPLY_SIZE);
- }
- /* Pathname */
- put_pathname (comm, filename);
-
- g_object_set_data (G_OBJECT (job), "start-index",
- GINT_TO_POINTER (start_index));
-
- g_vfs_afp_connection_send_command (conn, comm, NULL, enumerate_cb,
- G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
+ g_vfs_afp_volume_enumerate (afp_backend->volume, filename, start_index,
+ file_bitmap, dir_bitmap,
+ G_VFS_JOB (job)->cancellable, enumerate_cb, job);
}
static gboolean
@@ -3587,7 +1630,7 @@ try_query_settable_attributes (GVfsBackend *backend,
list = g_file_attribute_info_list_new ();
- if (afp_backend->vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
+ if (g_vfs_afp_volume_get_attributes (afp_backend->volume) & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
{
g_file_attribute_info_list_add (list,
G_FILE_ATTRIBUTE_UNIX_MODE,
@@ -3616,12 +1659,12 @@ try_query_settable_attributes (GVfsBackend *backend,
static void
set_attribute_set_unix_privs_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobSetAttribute *job = G_VFS_JOB_SET_ATTRIBUTE (user_data);
GError *err = NULL;
- if (!set_unix_privs_finish (afp_backend, res, &err))
+ if (!g_vfs_afp_volume_set_unix_privs_finish (volume, res, &err))
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
g_error_free (err);
@@ -3634,7 +1677,7 @@ set_attribute_set_unix_privs_cb (GObject *source_object, GAsyncResult *res, gpoi
static void
set_attribute_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobSetAttribute *job = G_VFS_JOB_SET_ATTRIBUTE (user_data);
GFileInfo *info;
@@ -3642,7 +1685,7 @@ set_attribute_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, g
guint32 uid, gid, permissions, ua_permissions;
- info = get_filedir_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -3665,10 +1708,10 @@ set_attribute_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, g
else if (strcmp (job->attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
permissions = job->value.uint32;
- set_unix_privs (afp_backend, job->filename,
- uid, gid, permissions, ua_permissions,
- G_VFS_JOB (job)->cancellable,
- set_attribute_set_unix_privs_cb, job);
+ g_vfs_afp_volume_set_unix_privs (volume, job->filename,
+ uid, gid, permissions, ua_permissions,
+ G_VFS_JOB (job)->cancellable,
+ set_attribute_set_unix_privs_cb, job);
}
static gboolean
@@ -3685,7 +1728,7 @@ try_set_attribute (GVfsBackend *backend,
if ((strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0 ||
strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0 ||
strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0)
- && afp_backend->vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
+ && g_vfs_afp_volume_get_attributes (afp_backend->volume) & AFP_VOLUME_ATTRIBUTES_BITMAP_SUPPORTS_UNIX_PRIVS)
{
if (type != G_FILE_ATTRIBUTE_TYPE_UINT32)
{
@@ -3697,10 +1740,12 @@ try_set_attribute (GVfsBackend *backend,
return TRUE;
}
- get_filedir_parms (afp_backend, filename, AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT,
- AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT,
- G_VFS_JOB (job)->cancellable, set_attribute_get_filedir_parms_cb,
- job);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, filename,
+ AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT,
+ AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT,
+ G_VFS_JOB (job)->cancellable,
+ set_attribute_get_filedir_parms_cb,
+ job);
return TRUE;
}
@@ -3716,13 +1761,13 @@ try_set_attribute (GVfsBackend *backend,
static void
query_fs_info_get_vol_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpServer *server = G_VFS_AFP_SERVER (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobQueryFsInfo *job = G_VFS_JOB_QUERY_FS_INFO (user_data);
GError *err = NULL;
GFileInfo *info;
- info = g_vfs_afp_server_get_vol_parms_finish (server, res, &err);
+ info = g_vfs_afp_volume_get_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -3762,9 +1807,9 @@ try_query_fs_info (GVfsBackend *backend,
if (vol_bitmap != 0)
{
- g_vfs_afp_server_get_vol_parms (afp_backend->server, afp_backend->volume_id,
- vol_bitmap, G_VFS_JOB (job)->cancellable,
- query_fs_info_get_vol_parms_cb, job);
+ g_vfs_afp_volume_get_parms (afp_backend->volume, vol_bitmap,
+ G_VFS_JOB (job)->cancellable,
+ query_fs_info_get_vol_parms_cb, job);
}
else
g_vfs_job_succeeded (G_VFS_JOB (job));
@@ -3775,14 +1820,14 @@ try_query_fs_info (GVfsBackend *backend,
static void
get_name_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobQueryInfo *job = G_VFS_JOB_QUERY_INFO (user_data);
char *name;
AfpMapIDFunction map_function;
guint outstanding_requests;
- name = map_id_finish (afp_backend, res, &map_function, NULL);
+ name = g_vfs_afp_volume_map_id_finish (volume, res, &map_function, NULL);
if (name)
{
switch (map_function)
@@ -3832,17 +1877,17 @@ set_root_info (GVfsBackendAfp *afp_backend, GFileInfo *info)
static void
query_info_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
GVfsJobQueryInfo *job = G_VFS_JOB_QUERY_INFO (user_data);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
-
GFileInfo *info;
GError *err = NULL;
GFileAttributeMatcher *matcher;
guint outstanding_requests;
- info = get_filedir_parms_finish (afp_backend, res, &err);
+ info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
if (!info)
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
@@ -3861,15 +1906,17 @@ query_info_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpoi
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_OWNER_USER))
{
- map_id (afp_backend, AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME, uid,
- G_VFS_JOB (job)->cancellable, get_name_cb, job);
+ g_vfs_afp_volume_map_id (volume,
+ AFP_MAP_ID_FUNCTION_USER_ID_TO_NAME, uid,
+ G_VFS_JOB (job)->cancellable, get_name_cb, job);
outstanding_requests++;
}
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_OWNER_USER_REAL))
{
- map_id (afp_backend, AFP_MAP_ID_FUNCTION_USER_ID_TO_UTF8_NAME, uid,
- G_VFS_JOB (job)->cancellable, get_name_cb, job);
+ g_vfs_afp_volume_map_id (volume,
+ AFP_MAP_ID_FUNCTION_USER_ID_TO_UTF8_NAME, uid,
+ G_VFS_JOB (job)->cancellable, get_name_cb, job);
outstanding_requests++;
}
}
@@ -3881,8 +1928,9 @@ query_info_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpoi
gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
- map_id (afp_backend, AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME, gid,
- G_VFS_JOB (job)->cancellable, get_name_cb, job);
+ g_vfs_afp_volume_map_id (volume,
+ AFP_MAP_ID_FUNCTION_GROUP_ID_TO_NAME, gid,
+ G_VFS_JOB (job)->cancellable, get_name_cb, job);
outstanding_requests++;
}
@@ -3919,9 +1967,10 @@ try_query_info (GVfsBackend *backend,
if (dir_bitmap != 0)
{
- get_filedir_parms (afp_backend, filename, 0, dir_bitmap,
- G_VFS_JOB (job)->cancellable,
- query_info_get_filedir_parms_cb, job);
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, filename,
+ 0, dir_bitmap,
+ G_VFS_JOB (job)->cancellable,
+ query_info_get_filedir_parms_cb, job);
}
else
{
@@ -3936,87 +1985,12 @@ try_query_info (GVfsBackend *backend,
file_bitmap = create_file_bitmap (afp_backend, matcher);
dir_bitmap = create_dir_bitmap (afp_backend, matcher);
- get_filedir_parms (afp_backend, filename, file_bitmap, dir_bitmap,
- G_VFS_JOB (job)->cancellable, query_info_get_filedir_parms_cb,
- job);
- }
-
- return TRUE;
-}
-
-static gboolean
-get_userinfo (GVfsBackendAfp *afp_backend,
- GCancellable *cancellable,
- GError **error)
-{
- GVfsAfpCommand *comm;
- guint16 bitmap;
- gboolean res;
-
- GVfsAfpReply *reply;
- AfpResultCode res_code;
-
- comm = g_vfs_afp_command_new (AFP_COMMAND_GET_USER_INFO);
- /* Flags, ThisUser = 1 */
- g_vfs_afp_command_put_byte (comm, 0x01);
- /* UserId */
- g_vfs_afp_command_put_int32 (comm, 0);
- /* Bitmap */
- bitmap = AFP_GET_USER_INFO_BITMAP_GET_UID_BIT | AFP_GET_USER_INFO_BITMAP_GET_GID_BIT;
- g_vfs_afp_command_put_uint16 (comm, bitmap);
-
- res = g_vfs_afp_connection_send_command_sync (afp_backend->server->conn,
- comm, cancellable, error);
- g_object_unref (comm);
- if (!res)
- return FALSE;
-
- reply = g_vfs_afp_connection_read_reply_sync (afp_backend->server->conn,
- cancellable, error);
- if (!reply)
- return FALSE;
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
-
- switch (res_code)
- {
- case AFP_RESULT_ACCESS_DENIED:
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Permission denied"));
- break;
- break;
- case AFP_RESULT_CALL_NOT_SUPPORTED:
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Command is not supported by server"));
- break;
- case AFP_RESULT_PWD_EXPIRED_ERR:
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("User's password has expired"));
- break;
- case AFP_RESULT_PWD_NEEDS_CHANGE_ERR:
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("User's password needs to be changed"));
- break;
-
- default:
- g_propagate_error (error, afp_result_code_to_gerror (res_code));
- break;
- }
- return FALSE;
+ g_vfs_afp_volume_get_filedir_parms (afp_backend->volume, filename,
+ file_bitmap, dir_bitmap,
+ G_VFS_JOB (job)->cancellable,
+ query_info_get_filedir_parms_cb, job);
}
- /* Bitmap */
- g_vfs_afp_reply_read_uint16 (reply, NULL);
- /* UID */
- g_vfs_afp_reply_read_uint32 (reply, &afp_backend->user_id);
- /* GID */
- g_vfs_afp_reply_read_uint32 (reply, &afp_backend->group_id);
-
- g_object_unref (reply);
-
return TRUE;
}
@@ -4031,10 +2005,6 @@ do_mount (GVfsBackend *backend,
gboolean res;
GError *err = NULL;
-
- GVfsAfpCommand *comm;
- GVfsAfpReply *reply;
- AfpResultCode res_code;
GMountSpec *afp_mount_spec;
char *server_name;
@@ -4046,56 +2016,18 @@ do_mount (GVfsBackend *backend,
NULL, G_VFS_JOB (job)->cancellable, &err);
if (!res)
goto error;
-
- /* Get User Info */
- if (!get_userinfo (afp_backend, G_VFS_JOB (job)->cancellable, &err))
- goto error;
-
- /* Open Volume */
- comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_VOL);
- /* pad byte */
- g_vfs_afp_command_put_byte (comm, 0);
- /* Volume Bitmap */
- g_vfs_afp_command_put_uint16 (comm, AFP_VOLUME_BITMAP_VOL_ID_BIT | AFP_VOLUME_BITMAP_ATTRIBUTE_BIT);
-
- /* VolumeName */
- g_vfs_afp_command_put_pascal (comm, afp_backend->volume);
-
- /* TODO: password? */
-
- res = g_vfs_afp_connection_send_command_sync (afp_backend->server->conn,
- comm, G_VFS_JOB (job)->cancellable,
- &err);
- g_object_unref (comm);
- if (!res)
- goto error;
- reply = g_vfs_afp_connection_read_reply_sync (afp_backend->server->conn,
- G_VFS_JOB (job)->cancellable, &err);
- if (!reply)
+ afp_backend->volume =
+ g_vfs_afp_server_mount_volume_sync (afp_backend->server, afp_backend->volume_name,
+ G_VFS_JOB (job)->cancellable, &err);
+ if (!afp_backend->volume)
goto error;
-
- res_code = g_vfs_afp_reply_get_result_code (reply);
- if (res_code != AFP_RESULT_NO_ERROR)
- {
- g_object_unref (reply);
- goto generic_error;
- }
-
- /* Volume Bitmap */
- g_vfs_afp_reply_read_uint16 (reply, NULL);
- /* Volume Attributes Bitmap */
- g_vfs_afp_reply_read_uint16 (reply, &afp_backend->vol_attrs_bitmap);
- /* Volume ID */
- g_vfs_afp_reply_read_uint16 (reply, &afp_backend->volume_id);
-
- g_object_unref (reply);
/* set mount info */
afp_mount_spec = g_mount_spec_new ("afp-volume");
g_mount_spec_set (afp_mount_spec, "host",
g_network_address_get_hostname (G_NETWORK_ADDRESS (afp_backend->addr)));
- g_mount_spec_set (afp_mount_spec, "volume", afp_backend->volume);
+ g_mount_spec_set (afp_mount_spec, "volume", afp_backend->volume_name);
if (afp_backend->user)
g_mount_spec_set (afp_mount_spec, "user", afp_backend->user);
@@ -4110,12 +2042,12 @@ do_mount (GVfsBackend *backend,
if (afp_backend->user)
/* Translators: first %s is volumename, second username and third servername */
display_name = g_strdup_printf (_("AFP volume %s for %s on %s"),
- afp_backend->volume, afp_backend->user,
+ afp_backend->volume_name, afp_backend->user,
server_name);
else
/* Translators: first %s is volumename and second servername */
display_name = g_strdup_printf (_("AFP volume %s on %s"),
- afp_backend->volume, server_name);
+ afp_backend->volume_name, server_name);
g_vfs_backend_set_display_name (backend, display_name);
g_free (display_name);
@@ -4129,13 +2061,6 @@ do_mount (GVfsBackend *backend,
error:
g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
return;
-
-generic_error:
- /* Translators: first %s is volumename and second servername */
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Couldn't mount AFP volume %s on %s"), afp_backend->volume,
- afp_backend->server->server_name);
- return;
}
static gboolean
@@ -4167,7 +2092,7 @@ try_mount (GVfsBackend *backend,
_("No volume specified"));
return TRUE;
}
- afp_backend->volume = g_strdup (volume);
+ afp_backend->volume_name = g_strdup (volume);
portstr = g_mount_spec_get (mount_spec, "port");
if (portstr != NULL)
@@ -4188,7 +2113,7 @@ g_vfs_backend_afp_init (GVfsBackendAfp *object)
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (object);
- afp_backend->volume = NULL;
+ afp_backend->volume_name = NULL;
afp_backend->user = NULL;
afp_backend->addr = NULL;
@@ -4199,9 +2124,11 @@ g_vfs_backend_afp_finalize (GObject *object)
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (object);
- g_free (afp_backend->volume);
g_free (afp_backend->user);
+ if (afp_backend->volume)
+ g_object_unref (afp_backend->volume);
+
if (afp_backend->addr)
g_object_unref (afp_backend->addr);
diff --git a/daemon/gvfsbackendafpbrowse.c b/daemon/gvfsbackendafpbrowse.c
index 1b5f1fc4..d3de8961 100644
--- a/daemon/gvfsbackendafpbrowse.c
+++ b/daemon/gvfsbackendafpbrowse.c
@@ -65,18 +65,6 @@ struct _GVfsBackendAfpBrowse
G_DEFINE_TYPE (GVfsBackendAfpBrowse, g_vfs_backend_afp_browse, G_VFS_TYPE_BACKEND);
-static gboolean
-is_root (const char *filename)
-{
- const char *p;
-
- p = filename;
- while (*p == '/')
- p++;
-
- return *p == 0;
-}
-
static void
get_volumes_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{