[gvfs] afp: implement copy



commit 208fed810f20271b7fba5c8edb6773644602f07c
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date:   Mon Aug 22 20:39:00 2011 +0200

    afp: implement copy

 daemon/gvfsbackendafp.c |  223 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 218 insertions(+), 5 deletions(-)
---
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index f4a80c3..51b0b96 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -50,6 +50,7 @@
 #include "gvfsjobmakedirectory.h"
 #include "gvfsjobsetdisplayname.h"
 #include "gvfsjobmove.h"
+#include "gvfsjobcopy.h"
 
 #include "gvfsafpserver.h"
 #include "gvfsafpconnection.h"
@@ -1598,11 +1599,13 @@ copy_file (GVfsBackendAfp     *afp_backend,
   /* pad byte */
   g_vfs_afp_command_put_byte (comm, 0);
 
-  /* VolumeID */
+  /* 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);
 
@@ -1647,6 +1650,208 @@ copy_file_finish (GVfsBackendAfp *afp_backend, GAsyncResult *res, GError **error
 /*
  * Backend code
  */
+
+typedef struct
+{
+  GVfsJobCopy  *job;
+  GAsyncResult *source_parms_res;
+  GAsyncResult *dest_parms_res;
+} CopyData;
+
+static void
+copy_data_free (CopyData *copy_data)
+{
+  g_object_unref (copy_data->source_parms_res);
+  g_object_unref (copy_data->dest_parms_res);
+
+  g_slice_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);
+  GVfsJobCopy *job = G_VFS_JOB_COPY (user_data);
+
+  GError *err = NULL;
+  
+  if (!copy_file_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 void
+copy_delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (source_object);
+  GVfsJobCopy *job = G_VFS_JOB_COPY (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;
+  }
+
+  copy_file (afp_backend, job->source, job->destination,
+             G_VFS_JOB (job)->cancellable, copy_copy_file_cb, job);
+}
+
+static void
+do_copy (CopyData *copy_data)
+{
+  GVfsJobCopy *job = copy_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, copy_data->source_parms_res, &err);
+  if (!info)
+  {
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), err);
+    g_error_free (err);
+    goto done;
+  }
+
+  /* If the source is a directory, don't fail with WOULD_RECURSE immediately,
+   * as that is less useful to the app. Better check for errors on the
+   * target instead.
+   */
+  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);
+  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);
+  }
+
+  /* Check target errors */
+  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 copy 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;
+    }
+  }
+
+  /* Now we fail if the source is a directory */
+  if (source_is_dir)
+  {
+    g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
+                      _("Can't recursively copy directory"));
+    goto done;
+  }
+
+  if (dest_exists)
+  {
+    delete (afp_backend, 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);
+  }
+  
+done:
+  copy_data_free (copy_data);
+  return;
+}
+
+static void
+copy_get_dest_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  CopyData *copy_data = (CopyData *)user_data;
+  
+  copy_data->dest_parms_res = g_object_ref (res);
+  if (copy_data->source_parms_res)
+    do_copy (copy_data);
+}
+
+static void
+copy_get_source_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  CopyData *copy_data = (CopyData *)user_data;
+
+  copy_data->source_parms_res = g_object_ref (res);
+  if (copy_data->dest_parms_res)
+    do_copy (copy_data);
+}
+
+static gboolean
+try_copy (GVfsBackend *backend,
+          GVfsJobCopy *job,
+          const char *source,
+          const char *destination,
+          GFileCopyFlags flags,
+          GFileProgressCallback progress_callback,
+          gpointer progress_callback_data)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+  CopyData *copy_data;
+
+  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);
+
+  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);  
+
+  return TRUE;
+}
+
 static void
 move_move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
@@ -1693,6 +1898,15 @@ typedef struct
 } MoveData;
 
 static void
+free_move_data (MoveData *move_data)
+{
+  g_object_unref (move_data->source_parms_res);
+  g_object_unref (move_data->dest_parms_res);
+
+  g_slice_free (MoveData, move_data);
+}
+
+static void
 do_move (MoveData *move_data)
 {
   GVfsJobMove *job = move_data->job;
@@ -1770,9 +1984,7 @@ do_move (MoveData *move_data)
                      job);
 
 done:
-  g_object_unref (move_data->source_parms_res);
-  g_object_unref (move_data->dest_parms_res);
-  g_slice_free (MoveData, move_data);
+  free_move_data (move_data);
   return;
 }
 
@@ -4071,6 +4283,7 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
   backend_class->try_make_directory = try_make_directory;
   backend_class->try_set_display_name = try_set_display_name;
   backend_class->try_move = try_move;
+  backend_class->try_copy = try_copy;
 }
 
 void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]