[gvfs] afp: implement move
- From: Christian Kellner <gicmo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] afp: implement move
- Date: Thu, 25 Aug 2011 19:28:26 +0000 (UTC)
commit 03aefc964366bc63c5de1ef94d8f6c863fe7a39c
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date: Tue Aug 2 23:10:26 2011 +0200
afp: implement move
daemon/gvfsafpconnection.h | 4 +
daemon/gvfsbackendafp.c | 434 +++++++++++++++++++++++++++++++++++++------
2 files changed, 377 insertions(+), 61 deletions(-)
---
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
index 4ee4cf0..9520e0b 100644
--- a/daemon/gvfsafpconnection.h
+++ b/daemon/gvfsafpconnection.h
@@ -191,6 +191,7 @@ typedef enum
AFP_COMMAND_LOGIN = 18,
AFP_COMMAND_LOGIN_CONT = 19,
AFP_COMMAND_MAP_NAME = 22,
+ AFP_COMMAND_MOVE_AND_RENAME = 23,
AFP_COMMAND_OPEN_VOL = 24,
AFP_COMMAND_OPEN_FORK = 26,
AFP_COMMAND_RENAME = 28,
@@ -214,6 +215,7 @@ typedef enum
AFP_RESULT_ACCESS_DENIED = -5000,
AFP_RESULT_AUTH_CONTINUE = -5001,
AFP_RESULT_BAD_UAM = -5002,
+ AFP_RESULT_CANT_MOVE = -5005,
AFP_RESULT_DIR_NOT_EMPTY = -5007,
AFP_RESULT_DISK_FULL = -5008,
AFP_RESULT_EOF_ERR = -5009,
@@ -232,6 +234,8 @@ typedef enum
AFP_RESULT_VOL_LOCKED = -5031,
AFP_RESULT_OBJECT_LOCKED = -5032,
AFP_RESULT_PWD_EXPIRED_ERR = -5042,
+ AFP_RESULT_INSIDE_SHARE_ERR = -5043,
+ AFP_RESULT_INSIDE_TRASH_ERR = -5044,
AFP_RESULT_PWD_NEEDS_CHANGE_ERR = -5045
} AfpResultCode;
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index a159c6c..54c8973 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -49,6 +49,7 @@
#include "gvfsjobdelete.h"
#include "gvfsjobmakedirectory.h"
#include "gvfsjobsetdisplayname.h"
+#include "gvfsjobmove.h"
#include "gvfsafpserver.h"
#include "gvfsafpconnection.h"
@@ -794,10 +795,10 @@ get_filedir_parms (GVfsBackendAfp *afp_backend,
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,
- get_filedir_parms_cb, cancellable,
- simple);
+ get_filedir_parms_cb, cancellable,
+ simple);
g_object_unref (comm);
}
@@ -1128,10 +1129,372 @@ create_file_finish (GVfsBackendAfp *afp_backend,
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);
+ g_simple_async_result_complete (simple);
+ 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_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ _("Permission denied"));
+ 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 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_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Got error code: %d from server"), res_code);
+ break;
+ }
+ }
+
+ g_simple_async_result_complete (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, 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;
+}
+
/*
* Backend code
*/
static void
+move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsJobMove *job = G_VFS_JOB_MOVE (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_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_MOVE:
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
+ _("Can't move directory into one of it's descendants"));
+ break;
+ case AFP_RESULT_INSIDE_SHARE_ERR:
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can't move sharepoint into a shared directory"));
+ break;
+ case AFP_RESULT_INSIDE_TRASH_ERR:
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can't move a shared directory into the Trash"));
+ break;
+ case AFP_RESULT_OBJECT_EXISTS:
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file already exists"));
+ break;
+ case AFP_RESULT_OBJECT_LOCKED:
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Object being moved is marked as 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,
+ _("Object being moved doesn't exist"));
+ break;
+ default:
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Got error code: %d from server"), res_code);
+ break;
+ }
+ return;
+ }
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+}
+
+static void
+move (GVfsBackendAfp *afp_backend, GVfsJobMove *job)
+{
+ GVfsAfpCommand *comm;
+ char *dirname, *basename;
+
+ 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, job->source);
+
+ /* DestPathname */
+ dirname = g_path_get_dirname (job->destination);
+ put_pathname (comm, dirname);
+ g_free (dirname);
+
+ /* NewName */
+ basename = g_path_get_basename (job->destination);
+ put_pathname (comm, basename);
+ g_free (basename);
+
+ g_vfs_afp_connection_send_command (afp_backend->server->conn, comm,
+ move_and_rename_cb, G_VFS_JOB (job)->cancellable,
+ job);
+ g_object_unref (comm);
+}
+
+static void
+move_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+ GVfsJobMove *job = G_VFS_JOB_MOVE (user_data);
+
+ GError *err = NULL;
+
+ if (!delete_finish (afp_backend, res, &err))
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
+ g_error_free (err);
+ return;
+ }
+
+ move (afp_backend, job);
+}
+
+typedef struct
+{
+ GVfsJobMove *job;
+ GAsyncResult *source_parms_res;
+ GAsyncResult *dest_parms_res;
+} MoveData;
+
+static void
+do_move (MoveData *move_data)
+{
+ GVfsJobMove *job = move_data->job;
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (job->backend);
+
+ GFileInfo *info;
+ GError *err = NULL;
+
+ gboolean source_is_dir;
+ gboolean dest_exists;
+ gboolean dest_is_dir;
+
+ info = get_filedir_parms_finish (afp_backend, move_data->source_parms_res, &err);
+ if (!info)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
+ g_error_free (err);
+ goto done;
+ }
+
+ 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);
+ if (!info)
+ {
+ if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_clear_error (&err);
+ dest_exists = FALSE;
+ }
+ else
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
+ g_error_free (err);
+ goto done;
+ }
+ }
+ else
+ {
+ dest_exists = TRUE;
+ dest_is_dir = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY ? TRUE : FALSE;
+ g_object_unref (info);
+ }
+
+ if (dest_exists)
+ {
+ if ((job->flags & G_FILE_COPY_OVERWRITE))
+ {
+ /* Always fail on dirs, even with overwrite */
+ if (dest_is_dir)
+ {
+ if (source_is_dir)
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_WOULD_MERGE,
+ _("Can't move directory over directory"));
+ else
+ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+ _("File is directory"));
+ goto done;
+ }
+ }
+ else
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS,
+ _("Target file already exists"));
+ goto done;
+ }
+
+ delete (afp_backend, job->destination, G_VFS_JOB (job)->cancellable,
+ move_delete_cb, job);
+ }
+ else
+ move (afp_backend, job);
+
+done:
+ g_object_unref (move_data->source_parms_res);
+ g_object_unref (move_data->dest_parms_res);
+ g_slice_free (MoveData, move_data);
+ return;
+}
+
+static void
+move_get_dest_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ MoveData *move_data = (MoveData *)user_data;
+
+ move_data->dest_parms_res = g_object_ref (res);
+ if (move_data->source_parms_res)
+ do_move (move_data);
+}
+
+static void
+move_get_source_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ MoveData *move_data = (MoveData *)user_data;
+
+ move_data->source_parms_res = g_object_ref (res);
+ if (move_data->dest_parms_res)
+ do_move (move_data);
+}
+
+static gboolean
+try_move (GVfsBackend *backend,
+ GVfsJobMove *job,
+ const char *source,
+ const char *destination,
+ GFileCopyFlags flags,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data)
+{
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+ MoveData *move_data;
+
+ 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);
+
+ 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);
+
+ return TRUE;
+}
+
+static void
rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
@@ -1389,58 +1752,20 @@ try_make_directory (GVfsBackend *backend,
}
static void
-delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+delete_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GVfsAfpConnection *afp_conn = G_VFS_AFP_CONNECTION (source_object);
+ GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
GVfsJobDelete *job = G_VFS_JOB_DELETE (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 (!delete_finish (afp_backend, 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_DIR_NOT_EMPTY:
- g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_EMPTY,
- _("Directory not empty"));
- 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 DeleteInhibit"));
- 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:
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Got error code: %d from server"), res_code);
- break;
- }
- return;
- }
-
g_vfs_job_succeeded (G_VFS_JOB (job));
}
@@ -1451,23 +1776,9 @@ try_delete (GVfsBackend *backend,
{
GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
- GVfsAfpCommand *comm;
-
- 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);
-
- g_vfs_afp_connection_send_command (afp_backend->server->conn, comm, delete_cb,
- G_VFS_JOB (job)->cancellable, job);
- g_object_unref (comm);
-
+ delete (afp_backend, filename, G_VFS_JOB (job)->cancellable,
+ delete_delete_cb, job);
+
return TRUE;
}
@@ -3257,6 +3568,7 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
backend_class->try_delete = try_delete;
backend_class->try_make_directory = try_make_directory;
backend_class->try_set_display_name = try_set_display_name;
+ backend_class->try_move = try_move;
}
void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]