diff options
-rw-r--r-- | daemon/Makefile.am | 8 | ||||
-rw-r--r-- | daemon/gvfsafpconnection.c | 40 | ||||
-rw-r--r-- | daemon/gvfsafpconnection.h | 1 | ||||
-rw-r--r-- | daemon/gvfsafpserver.c | 499 | ||||
-rw-r--r-- | daemon/gvfsafpserver.h | 25 | ||||
-rw-r--r-- | daemon/gvfsafputils.c | 12 | ||||
-rw-r--r-- | daemon/gvfsafputils.h | 10 | ||||
-rw-r--r-- | daemon/gvfsafpvolume.c | 3033 | ||||
-rw-r--r-- | daemon/gvfsafpvolume.h | 281 | ||||
-rw-r--r-- | daemon/gvfsbackendafp.c | 2643 | ||||
-rw-r--r-- | daemon/gvfsbackendafpbrowse.c | 12 |
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) { |