From 593d45b679b5dc9d6e757651043c520750400649 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 28 Jan 2009 13:02:37 +0000 Subject: [PATCH] - ObexFTP write support --- gvfs.spec | 11 +- obex-write-v3.patch | 440 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 obex-write-v3.patch diff --git a/gvfs.spec b/gvfs.spec index 6ad09ec..be97aea 100644 --- a/gvfs.spec +++ b/gvfs.spec @@ -1,7 +1,7 @@ Summary: Backends for the gio framework in GLib Name: gvfs Version: 1.1.4 -Release: 1%{?dist} +Release: 2%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.gtk.org @@ -34,6 +34,9 @@ Patch1: gvfs-0.99.2-archive-integration.patch # http://bugzilla.gnome.org/show_bug.cgi?id=565041 Patch2: gvfs-burn-move.patch +# http://bugzilla.gnome.org/show_bug.cgi?id=519071 +Patch3: obex-write-v3.patch + %description The gvfs package provides backend implementations for the gio framework in GLib. It includes ftp, sftp, cifs. @@ -116,6 +119,9 @@ media players (Media Transfer Protocol) to applications using gvfs. %setup -q %patch1 -p0 -b .archive-integration %patch2 -p0 -b .burn-move +pushd daemon/ +%patch3 -p0 -b .obexftp-write +popd %build @@ -256,6 +262,9 @@ update-desktop-database &> /dev/null ||: %changelog +* Wed Jan 28 2009 - Bastien Nocera - 1.1.4-2 +- ObexFTP write support + * Tue Jan 20 2009 Tomas Bzatek - 1.1.4-1 - Update to 1.1.4 diff --git a/obex-write-v3.patch b/obex-write-v3.patch new file mode 100644 index 0000000..cacaf67 --- /dev/null +++ b/obex-write-v3.patch @@ -0,0 +1,440 @@ +Index: obexftp-marshal.list +=================================================================== +--- obexftp-marshal.list (revision 2178) ++++ obexftp-marshal.list (working copy) +@@ -1,4 +1,5 @@ + VOID:STRING ++VOID:UINT64 + VOID:STRING,STRING + VOID:STRING,STRING,STRING + VOID:STRING,STRING,UINT64 +Index: gvfsbackendobexftp.c +=================================================================== +--- gvfsbackendobexftp.c (revision 2178) ++++ gvfsbackendobexftp.c (working copy) +@@ -17,7 +17,8 @@ + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * +- * Author: Bastien Nocera ++ * Authors: Bastien Nocera ++ * Cosimo Cecchi + */ + + #include +@@ -57,7 +58,8 @@ + + #define BDADDR_LEN 17 + +-#define ASYNC_SUCCESS 1 ++#define ASYNC_SUCCESS 2 ++#define ASYNC_RUNNING 1 + #define ASYNC_PENDING 0 + #define ASYNC_ERROR -1 + +@@ -443,6 +445,13 @@ + } + + static void ++_invalidate_cache_helper (GVfsBackendObexftp *op_backend) ++{ ++ g_free (op_backend->directory); ++ op_backend->directory = NULL; ++} ++ ++static void + error_occurred_cb (DBusGProxy *proxy, const gchar *error_name, const gchar *error_message, gpointer user_data) + { + GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data); +@@ -632,6 +641,10 @@ + + dbus_g_proxy_add_signal(op_backend->session_proxy, "TransferStarted", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); ++ dbus_g_proxy_add_signal(op_backend->session_proxy, "TransferCompleted", ++ G_TYPE_INVALID); ++ dbus_g_proxy_add_signal(op_backend->session_proxy, "TransferProgress", ++ G_TYPE_UINT64, G_TYPE_INVALID); + + /* Now wait until the device is connected */ + count = 0; +@@ -1186,7 +1199,327 @@ + g_print ("- do_enumerate\n"); + } + ++typedef struct { ++ GVfsBackendObexftp *op_backend; ++ GFileProgressCallback progress_callback; ++ gpointer progress_callback_data; ++ goffset total_bytes; ++} PushData; ++ + static void ++push_transfer_started_cb (DBusGProxy *proxy, ++ const gchar *filename, ++ const gchar *local_path, ++ guint64 total_bytes, ++ gpointer user_data) ++{ ++ PushData *job_data = (PushData *) user_data; ++ GVfsBackendObexftp *op_backend = job_data->op_backend; ++ ++ g_message ("transfer of %s to %s started", filename, local_path); ++ ++ g_mutex_lock (op_backend->mutex); ++ ++ op_backend->status = ASYNC_RUNNING; ++ job_data->total_bytes = (goffset) total_bytes; ++ job_data->progress_callback (0, job_data->total_bytes, ++ job_data->progress_callback_data); ++ ++ g_cond_signal (op_backend->cond); ++ g_mutex_unlock (op_backend->mutex); ++} ++ ++static void ++push_transfer_completed_cb (DBusGProxy *proxy, ++ gpointer user_data) ++{ ++ PushData *job_data = (PushData *) user_data; ++ GVfsBackendObexftp *op_backend = job_data->op_backend; ++ ++ g_message ("transfer completed"); ++ ++ g_mutex_lock (op_backend->mutex); ++ ++ op_backend->status = ASYNC_SUCCESS; ++ ++ g_cond_signal (op_backend->cond); ++ g_mutex_unlock (op_backend->mutex); ++} ++ ++static void ++push_transfer_progress_cb (DBusGProxy *proxy, ++ guint64 bytes_transferred, ++ gpointer user_data) ++{ ++ PushData *job_data = (PushData *) user_data; ++ ++ g_message ("transfer progress"); ++ ++ job_data->progress_callback ((goffset) bytes_transferred, ++ job_data->total_bytes, ++ job_data->progress_callback_data); ++} ++ ++static void ++push_data_free (PushData *job_data) ++{ ++ g_object_unref (job_data->op_backend); ++ g_slice_free (PushData, job_data); ++} ++ ++static gboolean ++_push_single_file_helper (GVfsBackendObexftp *op_backend, ++ GVfsJobPush *job, ++ const char *local_path, ++ const char *destination, ++ GError **error, ++ PushData *job_data) ++{ ++ char *dirname; ++ int success; ++ ++ dirname = g_path_get_dirname (destination); ++ ++ if (_change_directory (op_backend, dirname, error) == FALSE) ++ { ++ g_free (dirname); ++ return FALSE; ++ } ++ ++ g_free (dirname); ++ ++ if (g_vfs_job_is_cancelled (G_VFS_JOB (job))) ++ { ++ g_set_error (error, G_IO_ERROR, ++ G_IO_ERROR_CANCELLED, ++ _("Operation was cancelled")); ++ return FALSE; ++ } ++ ++ op_backend->status = ASYNC_PENDING; ++ ++ /* connect to the transfer signals */ ++ dbus_g_proxy_connect_signal (op_backend->session_proxy, "TransferStarted", ++ G_CALLBACK (push_transfer_started_cb), job_data, ++ NULL); ++ dbus_g_proxy_connect_signal (op_backend->session_proxy, "TransferCompleted", ++ G_CALLBACK (push_transfer_completed_cb), job_data, ++ NULL); ++ dbus_g_proxy_connect_signal (op_backend->session_proxy, "TransferProgress", ++ G_CALLBACK (push_transfer_progress_cb), job_data, ++ NULL); ++ ++ if (dbus_g_proxy_call (op_backend->session_proxy, "SendFile", error, ++ G_TYPE_STRING, local_path, G_TYPE_INVALID, ++ G_TYPE_INVALID) == FALSE) ++ { ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferStarted", ++ G_CALLBACK (push_transfer_started_cb), job_data); ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferCompleted", ++ G_CALLBACK (push_transfer_completed_cb), job_data); ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferProgress", ++ G_CALLBACK (push_transfer_progress_cb), job_data); ++ return FALSE; ++ } ++ ++ /* wait for the TransferStarted or ErrorOccurred signal */ ++ while (op_backend->status == ASYNC_PENDING) ++ g_cond_wait (op_backend->cond, op_backend->mutex); ++ ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferStarted", ++ G_CALLBACK (push_transfer_started_cb), job_data); ++ success = op_backend->status; ++ ++ /* we either got the operation running or an error */ ++ if (success == ASYNC_ERROR) ++ { ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferCompleted", ++ G_CALLBACK (push_transfer_completed_cb), job_data); ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferProgress", ++ G_CALLBACK (push_transfer_progress_cb), job_data); ++ ++ *error = g_error_copy (op_backend->error); ++ g_error_free (op_backend->error); ++ op_backend->error = NULL; ++ return FALSE; ++ } ++ ++ while (op_backend->status == ASYNC_RUNNING) ++ g_cond_wait (op_backend->cond, op_backend->mutex); ++ ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferCompleted", ++ G_CALLBACK (push_transfer_completed_cb), job_data); ++ dbus_g_proxy_disconnect_signal (op_backend->session_proxy, "TransferProgress", ++ G_CALLBACK (push_transfer_progress_cb), job_data); ++ success = op_backend->status; ++ ++ /* same as before, either we have success or an error */ ++ if (success == ASYNC_ERROR) ++ { ++ *error = g_error_copy (op_backend->error); ++ g_error_free (op_backend->error); ++ op_backend->error = NULL; ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void ++do_push (GVfsBackend *backend, ++ GVfsJobPush *job, ++ const char *destination, ++ const char *local_path, ++ GFileCopyFlags flags, ++ gboolean remove_source, ++ GFileProgressCallback progress_callback, ++ gpointer progress_callback_data) ++{ ++ GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (backend); ++ GError *error = NULL; ++ gboolean is_dir, overwrite, res; ++ GFileType target_type; ++ PushData *job_data; ++ GFileInfo *info; ++ ++ g_print ("+ do_push, destination: %s, local_path: %s\n", destination, local_path); ++ ++ g_mutex_lock (op_backend->mutex); ++ op_backend->doing_io = TRUE; ++ ++ overwrite = (flags & G_FILE_COPY_OVERWRITE); ++ is_dir = g_file_test (local_path, G_FILE_TEST_IS_DIR); ++ info = g_file_info_new (); ++ target_type = 0; ++ ++ if (g_vfs_job_is_cancelled (G_VFS_JOB (job))) ++ { ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_CANCELLED, ++ _("Operation was cancelled")); ++ return; ++ } ++ ++ res = _query_file_info_helper (backend, destination, info, &error); ++ ++ if (error != NULL) ++ { ++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) ++ { ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ ++ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); ++ g_error_free (error); ++ ++ return; ++ } ++ else ++ { ++ g_clear_error (&error); ++ res = TRUE; ++ } ++ } ++ ++ if (res) ++ target_type = g_file_info_get_file_type (info); ++ ++ g_object_unref (info); ++ ++ /* error handling */ ++ if (is_dir) ++ { ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ ++ if (target_type != 0) ++ { ++ if (overwrite) ++ { ++ if (target_type == G_FILE_TYPE_DIRECTORY) ++ { ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_WOULD_MERGE, ++ _("Can't copy directory over directory")); ++ return; ++ } ++ } ++ else ++ { ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_EXISTS, ++ _("Target file exists")); ++ return; ++ } ++ } ++ ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_WOULD_RECURSE, ++ _("Can't recursively copy directory")); ++ return; ++ } ++ else ++ { ++ if (target_type != 0) ++ { ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ ++ if (overwrite) ++ { ++ if (target_type == G_FILE_TYPE_DIRECTORY) ++ { ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_IS_DIRECTORY, ++ _("Can't copy file over directory")); ++ return; ++ } ++ } ++ else ++ { ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_EXISTS, ++ _("Target file exists")); ++ return; ++ } ++ } ++ } ++ ++ job_data = g_slice_new0 (PushData); ++ job_data->op_backend = g_object_ref (op_backend); ++ job_data->progress_callback = progress_callback; ++ job_data->progress_callback_data = progress_callback_data; ++ ++ /* start the actual transfer operation */ ++ if (_push_single_file_helper (op_backend, job, local_path, destination, ++ &error, job_data) == FALSE) ++ { ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ push_data_free (job_data); ++ ++ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); ++ } ++ ++ push_data_free (job_data); ++ ++ /* we called _query_file_info_helper (), so we need to invalidate the ++ * cache, as a query_info () will be called on us after we return. ++ */ ++ _invalidate_cache_helper (op_backend); ++ ++ g_vfs_job_succeeded (G_VFS_JOB (job)); ++ ++ op_backend->doing_io = FALSE; ++ g_mutex_unlock (op_backend->mutex); ++ ++ g_print ("- do_push\n"); ++} ++ ++static void + do_delete (GVfsBackend *backend, + GVfsJobDelete *job, + const char *filename) +@@ -1379,6 +1712,9 @@ + return; + } + ++ if (error) ++ g_clear_error (&error); ++ + if (g_vfs_job_is_cancelled (G_VFS_JOB (job))) + { + g_mutex_unlock (op_backend->mutex); +@@ -1413,17 +1749,23 @@ + G_TYPE_INVALID) == FALSE) + { + g_mutex_unlock (op_backend->mutex); ++ g_free (basename); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + return; + } + g_free (basename); + ++ /* reset the current directory so that we won't cache when querying ++ * info after this has succeeded. ++ */ ++ _invalidate_cache_helper (op_backend); ++ + g_vfs_job_succeeded (G_VFS_JOB (job)); + + g_mutex_unlock (op_backend->mutex); + +- g_print ("+ do_make_directory\n"); ++ g_print ("- do_make_directory\n"); + } + + static void +@@ -1443,6 +1785,7 @@ + backend_class->enumerate = do_enumerate; + backend_class->delete = do_delete; + backend_class->make_directory = do_make_directory; ++ backend_class->push = do_push; + + /* ErrorOccurred */ + dbus_g_object_register_marshaller (obexftp_marshal_VOID__STRING_STRING, +@@ -1451,6 +1794,9 @@ + /* TransferStarted */ + dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING_STRING_UINT64, + G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); ++ /* TransferProgress */ ++ dbus_g_object_register_marshaller(obexftp_marshal_VOID__UINT64, ++ G_TYPE_NONE, G_TYPE_UINT64, G_TYPE_INVALID); + /* SessionConnected */ + dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING, + G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);