diff options
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | daemon/Makefile.am | 5 | ||||
-rw-r--r-- | daemon/gvfsdaemon.c | 152 | ||||
-rw-r--r-- | daemon/gvfsdaemon.h | 9 | ||||
-rw-r--r-- | daemon/gvfsdaemonbackend.h | 5 | ||||
-rw-r--r-- | daemon/gvfsdaemonbackendtest.c | 57 | ||||
-rw-r--r-- | daemon/gvfsdaemonutils.c | 164 | ||||
-rw-r--r-- | daemon/gvfsdaemonutils.h | 7 | ||||
-rw-r--r-- | daemon/gvfsjob.c | 93 | ||||
-rw-r--r-- | daemon/gvfsjob.h | 34 | ||||
-rw-r--r-- | daemon/gvfsjobopenforread.c | 177 | ||||
-rw-r--r-- | daemon/gvfsjobopenforread.h | 47 | ||||
-rw-r--r-- | daemon/gvfsreadhandle.c | 113 | ||||
-rw-r--r-- | daemon/gvfsreadhandle.h | 54 | ||||
-rw-r--r-- | daemon/gvfsreadrequest.c | 111 | ||||
-rw-r--r-- | daemon/gvfsreadrequest.h | 54 | ||||
-rw-r--r-- | daemon/main.c | 4 | ||||
-rw-r--r-- | gvfs/gunixfileinputstream.c | 20 | ||||
-rw-r--r-- | gvfs/gvfsunixdbus.c | 79 | ||||
-rw-r--r-- | gvfs/gvfsunixdbus.h | 4 |
20 files changed, 896 insertions, 297 deletions
@@ -20,3 +20,7 @@ Add GFilterOutput/InputStream and derivates (buffered, data, charset conversion, Make backend pluggable local file access through the daemon for remote X clients? + +------------- + +continue on GVfsJobOpenForRead, especially the return part
\ No newline at end of file diff --git a/daemon/Makefile.am b/daemon/Makefile.am index ecea9ff1..8ffac31b 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -19,9 +19,10 @@ gvfs_daemon_SOURCES = \ gvfsdaemon.c gvfsdaemon.h \ gvfsdaemonbackend.c gvfsdaemonbackend.h \ gvfsdaemonbackendtest.c gvfsdaemonbackendtest.h \ - gvfsreadrequest.c gvfsreadrequest.h \ + gvfsreadhandle.c gvfsreadhandle.h \ gvfsdaemonutils.c gvfsdaemonutils.h \ - gvfsjob.c gvfsjob.g \ + gvfsjob.c gvfsjob.h \ + gvfsjobopenforread.c gvfsjobopenforread.h \ dbus-gmain.h dbus-gmain.c \ main.c diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c index 5819fd1e..19f5383b 100644 --- a/daemon/gvfsdaemon.c +++ b/daemon/gvfsdaemon.c @@ -11,6 +11,7 @@ #include <gvfsdaemon.h> #include <gvfsdaemonprotocol.h> #include <gvfsdaemonutils.h> +#include <gvfsjobopenforread.h> G_DEFINE_TYPE (GVfsDaemon, g_vfs_daemon, G_TYPE_OBJECT); @@ -21,12 +22,15 @@ enum { struct _GVfsDaemonPrivate { - GVfsDaemonBackend *backend; + GMutex *lock; /* protects the parts that are accessed by multiple threads */ char *mountpoint; gboolean active; -}; -static gint32 extra_fd_slot = -1; + GQueue *pending_jobs; + GQueue *jobs; /* protected by lock */ + guint queued_job_start; /* protected by lock */ + GList *read_handles; /* protected by lock */ +}; static void g_vfs_daemon_get_property (GObject *object, guint prop_id, @@ -60,8 +64,15 @@ g_vfs_daemon_finalize (GObject *object) daemon = G_VFS_DAEMON (object); + g_assert (daemon->priv->jobs->head == NULL); + g_assert (daemon->priv->pending_jobs->head == NULL); + g_queue_free (daemon->priv->jobs); + g_queue_free (daemon->priv->pending_jobs); + + g_object_unref (daemon->backend); + g_mutex_free (daemon->priv->lock); + g_free (daemon->priv->mountpoint); - g_object_ref (daemon->priv->backend); if (G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize) (*G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize) (object); @@ -79,9 +90,6 @@ g_vfs_daemon_class_init (GVfsDaemonClass *klass) gobject_class->get_property = g_vfs_daemon_get_property; gobject_class->constructor = g_vfs_daemon_constructor; - if (!dbus_connection_allocate_data_slot (&extra_fd_slot)) - g_error ("Unable to allocate data slot"); - g_object_class_install_property (gobject_class, PROP_MOUNTPOINT, g_param_spec_string ("mountpoint", @@ -90,7 +98,6 @@ g_vfs_daemon_class_init (GVfsDaemonClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - } static void @@ -99,6 +106,9 @@ g_vfs_daemon_init (GVfsDaemon *daemon) daemon->priv = G_TYPE_INSTANCE_GET_PRIVATE (daemon, G_TYPE_VFS_DAEMON, GVfsDaemonPrivate); + daemon->priv->lock = g_mutex_new (); + daemon->priv->jobs = g_queue_new (); + daemon->priv->pending_jobs = g_queue_new (); } static GObject* @@ -199,11 +209,12 @@ g_vfs_daemon_new (const char *mountpoint, daemon = g_object_new (G_TYPE_VFS_DAEMON, "mountpoint", mountpoint, NULL); - daemon->priv->backend = g_object_ref (backend); + daemon->backend = g_object_ref (backend); return daemon; } +#ifdef COMMENTED_OUT static int send_fd (int connection_fd, int fd) @@ -237,38 +248,6 @@ send_fd (int connection_fd, return ret; } -static void -daemon_handle_open_for_read (GVfsDaemon *daemon, - DBusConnection *conn, - DBusMessage *message) -{ - GVfsDaemonClass *class; - DBusMessage *reply; - DBusError derror; - const char *path_data; - int path_len; - char *path; - int fd; - GError *error; - GVfsReadRequest *read_request; - - class = G_VFS_DAEMON_GET_CLASS (daemon); - - dbus_error_init (&derror); - - read_request = NULL; - - if (!dbus_message_get_args (message, &derror, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &path_data, &path_len, - 0)) - { - reply = dbus_message_new_error (message, - derror.name, - derror.message); - dbus_error_free (&derror); - goto reply; - } error = NULL; read_request = g_vfs_read_request_new (&error); @@ -279,9 +258,6 @@ daemon_handle_open_for_read (GVfsDaemon *daemon, } else { - path = g_strndup (path_data, path_len); - g_vfs_read_request_set_filename (read_request, path); - g_free (path); reply = dbus_message_new_method_return (message); } @@ -298,12 +274,69 @@ daemon_handle_open_for_read (GVfsDaemon *daemon, /* TODO: Add request to table, etc */ } +#endif + +static gboolean +start_jobs_at_idle (gpointer data) +{ + GVfsDaemon *daemon = data; + GList *l, *next; + GVfsJob *job; + + g_mutex_lock (daemon->priv->lock); + daemon->priv->queued_job_start = 0; + g_mutex_unlock (daemon->priv->lock); + + l = daemon->priv->pending_jobs->head; + while (l != NULL) + { + job = l->data; + next = l->next; + + if (g_vfs_job_start (job)) + g_queue_delete_link (daemon->priv->pending_jobs, l); + + l = next; + } + + return FALSE; +} + +/* Called with lock held */ +static void +queue_start_jobs_at_idle (GVfsDaemon *daemon) +{ + if (daemon->priv->queued_job_start == 0) + daemon->priv->queued_job_start = g_idle_add (start_jobs_at_idle, daemon); +} + +/* NOTE: Might be emitted on a thread */ +static void +job_finished_callback (GVfsJob *job, + GVfsDaemon *daemon) +{ + g_mutex_lock (daemon->priv->lock); + g_queue_remove (daemon->priv->jobs, job); + queue_start_jobs_at_idle (daemon); + g_mutex_unlock (daemon->priv->lock); + g_object_unref (job); } static void -close_wrapper (gpointer p) +start_or_queue_job (GVfsDaemon *daemon, + GVfsJob *job) { - close (GPOINTER_TO_INT (p)); + g_mutex_lock (daemon->priv->lock); + g_queue_push_tail (daemon->priv->jobs, job); + g_mutex_unlock (daemon->priv->lock); + g_signal_connect (job, "finished", (GCallback)job_finished_callback, daemon); + + /* Can we start the job immediately */ + if (!g_vfs_job_start (job)) + { + /* Didn't start, queue as pending */ + g_queue_push_tail (daemon->priv->pending_jobs, job); + } } static void @@ -323,9 +356,7 @@ daemon_peer_connection_setup (GVfsDaemon *daemon, g_printerr ("Failed to register object with new dbus peer connection.\n"); } - if (!dbus_connection_set_data (dbus_conn, extra_fd_slot, GINT_TO_POINTER (extra_fd), close_wrapper)) - g_error ("Out of memory"); - + dbus_connection_add_fd_send_fd (dbus_conn, extra_fd); } #ifdef __linux__ @@ -620,6 +651,7 @@ daemon_handle_get_connection (DBusConnection *conn, g_io_channel_unref (channel); reply = dbus_message_new_method_return (message); + /* TODO: Check OOM */ dbus_message_append_args (reply, DBUS_TYPE_STRING, &address1, DBUS_TYPE_STRING, &address2, @@ -656,7 +688,9 @@ daemon_message_func (DBusConnection *conn, gpointer data) { GVfsDaemon *daemon = data; - + GVfsJob *job; + + job = NULL; if (dbus_message_is_method_call (message, G_VFS_DBUS_DAEMON_INTERFACE, G_VFS_DBUS_OP_GET_CONNECTION)) @@ -664,10 +698,13 @@ daemon_message_func (DBusConnection *conn, else if (dbus_message_is_method_call (message, G_VFS_DBUS_DAEMON_INTERFACE, G_VFS_DBUS_OP_OPEN_FOR_READ)) - daemon_handle_open_for_read (daemon, conn, message); + job = g_vfs_job_open_for_read_new (daemon, conn, message); else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (job) + start_or_queue_job (daemon, job); + return DBUS_HANDLER_RESULT_HANDLED; } @@ -676,3 +713,16 @@ gboolean { return daemon->priv->active; } + + +/* Calling this on a thread is allowed */ +void +g_vfs_daemon_register_read_handle (GVfsDaemon *daemon, + GVfsReadHandle *handle) +{ + g_mutex_lock (daemon->priv->lock); + daemon->priv->read_handles = g_list_append (daemon->priv->read_handles, + handle); + g_mutex_unlock (daemon->priv->lock); +} + diff --git a/daemon/gvfsdaemon.h b/daemon/gvfsdaemon.h index 6cae46d4..825a1d77 100644 --- a/daemon/gvfsdaemon.h +++ b/daemon/gvfsdaemon.h @@ -2,7 +2,7 @@ #define __G_VFS_DAEMON_H__ #include <glib-object.h> -#include <gvfsdaemonbackend.h> +#include <gvfsreadhandle.h> G_BEGIN_DECLS @@ -17,10 +17,14 @@ typedef struct _GVfsDaemon GVfsDaemon; typedef struct _GVfsDaemonClass GVfsDaemonClass; typedef struct _GVfsDaemonPrivate GVfsDaemonPrivate; +/* Placed here to fix circular ref problems in headers */ +typedef struct _GVfsDaemonBackend GVfsDaemonBackend; + struct _GVfsDaemon { GObject parent_instance; + GVfsDaemonBackend *backend; GVfsDaemonPrivate *priv; }; @@ -38,6 +42,9 @@ GVfsDaemon *g_vfs_daemon_new (const char *mountpoint, GVfsDaemonBackend *backend); gboolean g_vfs_daemon_is_active (GVfsDaemon *daemon); +void g_vfs_daemon_register_read_handle (GVfsDaemon *daemon, + GVfsReadHandle *handle); + G_END_DECLS diff --git a/daemon/gvfsdaemonbackend.h b/daemon/gvfsdaemonbackend.h index 9cdb9816..842b6e63 100644 --- a/daemon/gvfsdaemonbackend.h +++ b/daemon/gvfsdaemonbackend.h @@ -1,8 +1,9 @@ #ifndef __G_VFS_DAEMON_BACKEND_H__ #define __G_VFS_DAEMON_BACKEND_H__ -#include <gvfsjob.h> #include <gvfs/gvfstypes.h> +#include <gvfsdaemon.h> +#include <gvfsjob.h> G_BEGIN_DECLS @@ -13,7 +14,7 @@ G_BEGIN_DECLS #define G_IS_VFS_DAEMON_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_DAEMON_BACKEND)) #define G_VFS_DAEMON_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_DAEMON_BACKEND, GVfsDaemonBackendClass)) -typedef struct _GVfsDaemonBackend GVfsDaemonBackend; +/* GVfsDaemonBackend defined in gvfsdaemon.h to fix circular defines */ typedef struct _GVfsDaemonBackendClass GVfsDaemonBackendClass; typedef gpointer GVfsHandle; diff --git a/daemon/gvfsdaemonbackendtest.c b/daemon/gvfsdaemonbackendtest.c index 3205c945..4c70549b 100644 --- a/daemon/gvfsdaemonbackendtest.c +++ b/daemon/gvfsdaemonbackendtest.c @@ -1,9 +1,21 @@ #include <config.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +#include <glib/gstdio.h> + #include "gvfsdaemonbackendtest.h" +#include "gvfsjobopenforread.h" G_DEFINE_TYPE (GVfsDaemonBackendTest, g_vfs_daemon_backend_test, G_TYPE_VFS_DAEMON_BACKEND); +static gboolean open_for_read (GVfsDaemonBackend *backend, + GVfsJobOpenForRead *job, + char *filename); + static void g_vfs_daemon_backend_test_finalize (GObject *object) { @@ -19,11 +31,11 @@ static void g_vfs_daemon_backend_test_class_init (GVfsDaemonBackendTestClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - //GVfsDaemonBackendClass *backend_class = G_VFS_DAEMON_BACKEND_CLASS (klass); + GVfsDaemonBackendClass *backend_class = G_VFS_DAEMON_BACKEND_CLASS (klass); gobject_class->finalize = g_vfs_daemon_backend_test_finalize; - //backend_class->open_for_read = open_for_read; + backend_class->open_for_read = open_for_read; } static void @@ -40,3 +52,44 @@ g_vfs_daemon_backend_test_new (void) return backend; } +static gboolean +open_idle_cb (gpointer data) +{ + GVfsJobOpenForRead *job = data; + int fd; + + fd = g_open (job->filename, O_RDONLY); + if (fd == -1) + { + g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR, + g_file_error_from_errno (errno), + "Error opening file %s: %s", + job->filename, g_strerror (errno)); + } + else + { + g_vfs_job_open_for_read_set_handle (job, GINT_TO_POINTER (fd)); + g_vfs_job_succeeded (G_VFS_JOB (job)); + } + return FALSE; +} + +static gboolean +open_for_read (GVfsDaemonBackend *backend, + GVfsJobOpenForRead *job, + char *filename) +{ + GError *error; + + if (strcmp (filename, "/fail") == 0) + { + error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_IO, "Test error"); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + return TRUE; + } + else + { + g_idle_add (open_idle_cb, job); + return TRUE; + } +} diff --git a/daemon/gvfsdaemonutils.c b/daemon/gvfsdaemonutils.c index 132bfd13..2dc3fa04 100644 --- a/daemon/gvfsdaemonutils.c +++ b/daemon/gvfsdaemonutils.c @@ -1,18 +1,168 @@ #include <config.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <glib/gthread.h> +#include <glib/gi18n.h> #include "gvfsdaemonutils.h" +static gint32 extra_fd_slot = -1; +static GStaticMutex extra_lock = G_STATIC_MUTEX_INIT; + +typedef struct { + int extra_fd; + int fd_count; +} ConnectionExtra; + +/* We use _ for escaping, so its not valid */ +#define VALID_INITIAL_NAME_CHARACTER(c) \ + ( ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z') ) +#define VALID_NAME_CHARACTER(c) \ + ( ((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z')) + + +static void +append_escaped_name (GString *s, + const char *unescaped) +{ + char c; + gboolean first; + static const gchar hex[16] = "0123456789ABCDEF"; + + while ((c = *unescaped++) != 0) + { + if (first) + { + if (VALID_INITIAL_NAME_CHARACTER (c)) + { + g_string_append_c (s, c); + continue; + } + } + else + { + if (VALID_NAME_CHARACTER (c)) + { + g_string_append_c (s, c); + continue; + } + } + + first = FALSE; + g_string_append_c (s, '_'); + g_string_append_c (s, hex[((guchar)c) >> 4]); + g_string_append_c (s, hex[((guchar)c) & 0xf]); + } +} + DBusMessage * dbus_message_new_error_from_gerror (DBusMessage *message, GError *error) { - char *error_name; DBusMessage *reply; - - error_name = g_strdup_printf ("org.glib.GError.%s.%d", - g_quark_to_string (error->domain), - error->code); - reply = dbus_message_new_error (message, error_name, error->message); - g_free (error_name); + GString *str; + + str = g_string_new ("org.glib.GError."); + append_escaped_name (str, g_quark_to_string (error->domain)); + g_string_append_printf (str, ".c%d", error->code); + reply = dbus_message_new_error (message, str->str, error->message); + g_string_free (str, TRUE); return reply; } + +static void +free_extra (gpointer p) +{ + ConnectionExtra *extra = p; + close (extra->extra_fd); + g_free (extra); +} + +void +dbus_connection_add_fd_send_fd (DBusConnection *connection, + int extra_fd) +{ + ConnectionExtra *extra; + + if (extra_fd_slot == -1 && + !dbus_connection_allocate_data_slot (&extra_fd_slot)) + g_error ("Unable to allocate data slot"); + + extra = g_new0 (ConnectionExtra, 1); + extra->extra_fd = extra_fd; + + if (!dbus_connection_set_data (connection, extra_fd_slot, extra, free_extra)) + g_error ("Out of memory"); +} + +static int +send_fd (int connection_fd, + int fd) +{ + struct msghdr msg; + struct iovec vec; + char buf[1] = {'x'}; + char ccmsg[CMSG_SPACE (sizeof (fd))]; + struct cmsghdr *cmsg; + int ret; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + vec.iov_base = buf; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof (ccmsg); + cmsg = CMSG_FIRSTHDR (&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN (sizeof(fd)); + *(int*)CMSG_DATA (cmsg) = fd; + msg.msg_controllen = cmsg->cmsg_len; + msg.msg_flags = 0; + + ret = sendmsg (connection_fd, &msg, 0); + g_print ("sendmesg ret: %d\n", ret); + return ret; +} + +gboolean +dbus_connection_send_fd (DBusConnection *connection, + int fd, + int *fd_id, + GError **error) +{ + ConnectionExtra *extra; + + g_assert (extra_fd_slot != -1); + + extra = dbus_connection_get_data (connection, extra_fd_slot); + + g_assert (extra != NULL); + + g_static_mutex_lock (&extra_lock); + + if (send_fd (extra->extra_fd, fd) == -1) + { + g_set_error (error, G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Error sending fd: %s"), + g_strerror (errno)); + return FALSE; + } + + *fd_id = extra->fd_count++; + + g_static_mutex_unlock (&extra_lock); + + return TRUE; +} diff --git a/daemon/gvfsdaemonutils.h b/daemon/gvfsdaemonutils.h index 7f205950..50654ab4 100644 --- a/daemon/gvfsdaemonutils.h +++ b/daemon/gvfsdaemonutils.h @@ -3,12 +3,17 @@ #include <glib-object.h> #include <dbus/dbus.h> -#include <gvfsreadrequest.h> G_BEGIN_DECLS DBusMessage *dbus_message_new_error_from_gerror (DBusMessage *message, GError *error); +void dbus_connection_add_fd_send_fd (DBusConnection *connection, + int extra_fd); +gboolean dbus_connection_send_fd (DBusConnection *connection, + int fd, + int *fd_id, + GError **error); G_END_DECLS diff --git a/daemon/gvfsjob.c b/daemon/gvfsjob.c index 4e488385..c140e922 100644 --- a/daemon/gvfsjob.c +++ b/daemon/gvfsjob.c @@ -10,10 +10,11 @@ #include <glib/gi18n.h> #include "gvfsjob.h" -G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_VFS_JOB); +G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_OBJECT); enum { - CANCEL, + CANCELLED, + FINISHED, LAST_SIGNAL }; @@ -40,11 +41,19 @@ g_vfs_job_class_init (GVfsJobClass *klass) gobject_class->finalize = g_vfs_job_finalize; - signals[CANCEL] = - g_signal_new ("done", + signals[CANCELLED] = + g_signal_new ("cancelled", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVfsJobClass, cancel), + G_STRUCT_OFFSET (GVfsJobClass, cancelled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[FINISHED] = + g_signal_new ("finished", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVfsJobClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); @@ -56,6 +65,15 @@ g_vfs_job_init (GVfsJob *job) { } +gboolean +g_vfs_job_start (GVfsJob *job) +{ + GVfsJobClass *class; + + class = G_VFS_JOB_GET_CLASS (job); + return class->start (job); +} + void g_vfs_job_cancel (GVfsJob *job) { @@ -63,16 +81,75 @@ g_vfs_job_cancel (GVfsJob *job) return; job->cancelled = TRUE; - g_signal_emit (job, signals[CANCEL], 0); + g_signal_emit (job, signals[CANCELLED], 0); +} + +static void +g_vfs_job_send_reply (GVfsJob *job) +{ + GVfsJobClass *class; + + class = G_VFS_JOB_GET_CLASS (job); + class->send_reply (job); +} + +void +g_vfs_job_failed (GVfsJob *job, + GQuark domain, + gint code, + const gchar *format, + ...) +{ + va_list args; + char *message; + + if (job->failed) + return; + + job->failed = TRUE; + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + job->error = g_error_new (domain, code, message); + g_free (message); + + g_vfs_job_send_reply (job); } void -g_vfs_job_set_failed (GVfsJob *job, - GError *error) +g_vfs_job_failed_from_error (GVfsJob *job, + GError *error) { if (job->failed) return; job->failed = TRUE; job->error = g_error_copy (error); + g_vfs_job_send_reply (job); +} + +void +g_vfs_job_succeeded (GVfsJob *job) +{ + job->failed = FALSE; + g_vfs_job_send_reply (job); +} + + +gboolean +g_vfs_job_is_finished (GVfsJob *job) +{ + return job->finished; +} + +/* Might be called on an i/o thread */ +void +g_vfs_job_emit_finished (GVfsJob *job) +{ + g_assert (!job->finished); + + job->finished = TRUE; + g_signal_emit (job, signals[FINISHED], 0); } diff --git a/daemon/gvfsjob.h b/daemon/gvfsjob.h index 84f29409..9f9e86da 100644 --- a/daemon/gvfsjob.h +++ b/daemon/gvfsjob.h @@ -2,6 +2,7 @@ #define __G_VFS_JOB_H__ #include <glib-object.h> +#include <gvfsdaemon.h> G_BEGIN_DECLS @@ -12,20 +13,22 @@ G_BEGIN_DECLS #define G_IS_VFS_JOB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB)) #define G_VFS_JOB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB, GVfsJobClass)) -typedef struct _GVfsJob GVfsJob; -typedef struct _GVfsJobClass GVfsJobClass; +typedef struct _GVfsJob GVfsJob; +typedef struct _GVfsJobClass GVfsJobClass; -/* Temp typedefs */ -typedef GVfsJob GVfsJobOpenForRead; -typedef GVfsJob GVfsJobRead; -typedef GVfsJob GVfsJobReadSeek; +/* Define these here to avoid circular includes */ +typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead; +typedef struct _GVfsJobRead GVfsJobRead; +typedef struct _GVfsJobReadSeek GVfsJobReadSeek; struct _GVfsJob { GObject parent_instance; + GVfsDaemon *daemon; guint failed : 1; guint cancelled : 1; + guint finished : 1; GError *error; }; @@ -34,20 +37,29 @@ struct _GVfsJobClass GObjectClass parent_class; /* signals */ - void (*cancel) (GVfsJob *job); + void (*cancelled) (GVfsJob *job); void (*finished) (GVfsJob *job); /* vtable */ gboolean (*start) (GVfsJob *job); - + void (*send_reply) (GVfsJob *job); }; GType g_vfs_job_get_type (void) G_GNUC_CONST; -void g_vfs_job_cancel (GVfsJob *job); -void g_vfs_job_set_failed (GVfsJob *job, - GError *error); +gboolean g_vfs_job_is_finished (GVfsJob *job); +void g_vfs_job_cancel (GVfsJob *job); +gboolean g_vfs_job_start (GVfsJob *job); +void g_vfs_job_emit_finished (GVfsJob *job); +void g_vfs_job_failed (GVfsJob *job, + GQuark domain, + gint code, + const gchar *format, + ...) G_GNUC_PRINTF (4, 5); +void g_vfs_job_failed_from_error (GVfsJob *job, + GError *error); +void g_vfs_job_succeeded (GVfsJob *job); G_END_DECLS diff --git a/daemon/gvfsjobopenforread.c b/daemon/gvfsjobopenforread.c new file mode 100644 index 00000000..43fcb7d9 --- /dev/null +++ b/daemon/gvfsjobopenforread.c @@ -0,0 +1,177 @@ +#include <config.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <glib.h> +#include <dbus/dbus.h> +#include <glib/gi18n.h> +#include "gvfsreadhandle.h" +#include "gvfsjobopenforread.h" +#include "gvfsdaemonutils.h" + +G_DEFINE_TYPE (GVfsJobOpenForRead, g_vfs_job_open_for_read, G_TYPE_VFS_JOB); + +static gboolean start (GVfsJob *job); +static void send_reply (GVfsJob *job); + +static void +g_vfs_job_open_for_read_finalize (GObject *object) +{ + GVfsJobOpenForRead *job; + + job = G_VFS_JOB_OPEN_FOR_READ (object); + + if (job->message) + dbus_message_unref (job->message); + + /* TODO: manage backend_handle if not put in readhandle */ + + g_free (job->filename); + + if (G_OBJECT_CLASS (g_vfs_job_open_for_read_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_job_open_for_read_parent_class)->finalize) (object); +} + +static void +g_vfs_job_open_for_read_class_init (GVfsJobOpenForReadClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass); + + gobject_class->finalize = g_vfs_job_open_for_read_finalize; + + job_class->start = start; + job_class->send_reply = send_reply; +} + +static void +g_vfs_job_open_for_read_init (GVfsJobOpenForRead *job) +{ +} + +GVfsJob * +g_vfs_job_open_for_read_new (GVfsDaemon *daemon, + DBusConnection *connection, + DBusMessage *message) +{ + GVfsJobOpenForRead *job; + DBusMessage *reply; + DBusError derror; + int path_len; + const char *path_data; + + dbus_error_init (&derror); + if (!dbus_message_get_args (message, &derror, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &path_data, &path_len, + 0)) + { + reply = dbus_message_new_error (message, + derror.name, + derror.message); + dbus_error_free (&derror); + + dbus_connection_send (connection, reply, NULL); + return NULL; + } + + job = g_object_new (G_TYPE_VFS_JOB_OPEN_FOR_READ, NULL); + + G_VFS_JOB (job)->daemon = daemon; + job->connection = connection; /* TODO: ref? */ + job->message = dbus_message_ref (message); + job->filename = g_strndup (path_data, path_len); + + return G_VFS_JOB (job); +} + +static gboolean +start (GVfsJob *job) +{ + GVfsDaemonBackendClass *class; + GVfsJobOpenForRead *op_job = G_VFS_JOB_OPEN_FOR_READ (job); + + class = G_VFS_DAEMON_BACKEND_GET_CLASS (job->daemon->backend); + + return class->open_for_read (job->daemon->backend, + op_job, + op_job->filename); +} + +void +g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job, + GVfsHandle *handle) +{ + job->backend_handle = handle; +} + +/* Might be called on an i/o thread */ +static DBusMessage * +create_reply (GVfsJob *job, + DBusConnection *connection, + DBusMessage *message) +{ + GVfsJobOpenForRead *open_job = G_VFS_JOB_OPEN_FOR_READ (job); + GVfsReadHandle *handle; + DBusMessage *reply; + GError *error; + int fd_id; + gboolean res; + + g_assert (open_job->backend_handle != NULL); + + error = NULL; + handle = g_vfs_read_handle_new (&error); + if (handle == NULL) + { + reply = dbus_message_new_error_from_gerror (message, error); + g_error_free (error); + return reply; + } + + if (!dbus_connection_send_fd (connection, + g_vfs_read_handle_get_remote_fd (handle), + &fd_id, &error)) + { + reply = dbus_message_new_error_from_gerror (message, error); + g_error_free (error); + g_object_unref (handle); + return reply; + } + + reply = dbus_message_new_method_return (message); + res = dbus_message_append_args (reply, + DBUS_TYPE_UINT32, &fd_id, + DBUS_TYPE_INVALID); + + g_vfs_read_handle_close_remote_fd (handle); + g_vfs_read_handle_set_data (handle, open_job->backend_handle); + g_vfs_daemon_register_read_handle (job->daemon, handle); + open_job->backend_handle = NULL; + + return reply; +} + +/* Might be called on an i/o thread */ +static void +send_reply (GVfsJob *job) +{ + GVfsJobOpenForRead *open_job = G_VFS_JOB_OPEN_FOR_READ (job); + DBusMessage *reply; + + if (job->failed) + reply = dbus_message_new_error_from_gerror (open_job->message, job->error); + else + reply = create_reply (job, open_job->connection, open_job->message); + + g_assert (reply != NULL); + + /* Queues reply (threadsafely), actually sends it in mainloop */ + dbus_connection_send (open_job->connection, reply, NULL); + dbus_message_unref (reply); + + g_vfs_job_emit_finished (job); +} diff --git a/daemon/gvfsjobopenforread.h b/daemon/gvfsjobopenforread.h new file mode 100644 index 00000000..f86cf0c1 --- /dev/null +++ b/daemon/gvfsjobopenforread.h @@ -0,0 +1,47 @@ +#ifndef __G_VFS_JOB_OPEN_FOR_READ_H__ +#define __G_VFS_JOB_OPEN_FOR_READ_H__ + +#include <dbus/dbus.h> +#include <gvfsjob.h> +#include <gvfsdaemonbackend.h> + + +G_BEGIN_DECLS + +#define G_TYPE_VFS_JOB_OPEN_FOR_READ (g_vfs_job_open_for_read_get_type ()) +#define G_VFS_JOB_OPEN_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForRead)) +#define G_VFS_JOB_OPEN_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForReadClass)) +#define G_IS_VFS_JOB_OPEN_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ)) +#define G_IS_VFS_JOB_OPEN_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_OPEN_FOR_READ)) +#define G_VFS_JOB_OPEN_FOR_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForReadClass)) + +/* GVfsJobOpenForRead declared in gvfsjob.h */ +typedef struct _GVfsJobOpenForReadClass GVfsJobOpenForReadClass; + +struct _GVfsJobOpenForRead +{ + GVfsJob parent_instance; + + DBusConnection *connection; + DBusMessage *message; + char *filename; + GVfsHandle *backend_handle; +}; + +struct _GVfsJobOpenForReadClass +{ + GVfsJobClass parent_class; +}; + +GType g_vfs_job_open_for_read_get_type (void) G_GNUC_CONST; + +GVfsJob *g_vfs_job_open_for_read_new (GVfsDaemon *daemon, + DBusConnection *connection, + DBusMessage *message); + +void g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job, + GVfsHandle *handle); + +G_END_DECLS + +#endif /* __G_VFS_JOB_OPEN_FOR_READ_H__ */ diff --git a/daemon/gvfsreadhandle.c b/daemon/gvfsreadhandle.c new file mode 100644 index 00000000..24e6aed6 --- /dev/null +++ b/daemon/gvfsreadhandle.c @@ -0,0 +1,113 @@ +#include <config.h> + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <glib.h> +#include <glib-object.h> +#include <glib/gi18n.h> +#include <dbus-gmain.h> +#include <gvfsreadhandle.h> + +G_DEFINE_TYPE (GVfsReadHandle, g_vfs_read_handle, G_TYPE_OBJECT); + +enum { + PROP_0, +}; + +struct _GVfsReadHandlePrivate +{ + int fd; + int remote_fd; + + gpointer data; +}; + +static void +g_vfs_read_handle_finalize (GObject *object) +{ + GVfsReadHandle *read_handle; + + read_handle = G_VFS_READ_HANDLE (object); + + if (read_handle->priv->fd != -1) + close (read_handle->priv->fd); + + if (read_handle->priv->remote_fd != -1) + close (read_handle->priv->remote_fd); + + if (G_OBJECT_CLASS (g_vfs_read_handle_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_read_handle_parent_class)->finalize) (object); +} + +static void +g_vfs_read_handle_class_init (GVfsReadHandleClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GVfsReadHandlePrivate)); + + gobject_class->finalize = g_vfs_read_handle_finalize; +} + +static void +g_vfs_read_handle_init (GVfsReadHandle *handle) +{ + handle->priv = G_TYPE_INSTANCE_GET_PRIVATE (handle, + G_TYPE_VFS_READ_HANDLE, + GVfsReadHandlePrivate); + handle->priv->fd = -1; + handle->priv->remote_fd = -1; +} + +GVfsReadHandle * +g_vfs_read_handle_new (GError **error) +{ + GVfsReadHandle *handle; + int socket_fds[2]; + int ret; + + ret = socketpair (AF_UNIX, SOCK_STREAM, 0, socket_fds); + if (ret == -1) + { + g_set_error (error, G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Error creating socket pair")); + return NULL; + } + + handle = g_object_new (G_TYPE_VFS_READ_HANDLE, NULL); + handle->priv->fd = socket_fds[0]; + handle->priv->remote_fd = socket_fds[1]; + + return handle; +} + +int +g_vfs_read_handle_get_fd (GVfsReadHandle *handle) +{ + return handle->priv->fd; +} + +int + g_vfs_read_handle_get_remote_fd (GVfsReadHandle *handle) +{ + return handle->priv->remote_fd; +} + +void + g_vfs_read_handle_close_remote_fd (GVfsReadHandle *handle) +{ + close (handle->priv->remote_fd); + handle->priv->remote_fd = -1; +} + +void +g_vfs_read_handle_set_data (GVfsReadHandle *read_handle, + gpointer data) +{ + read_handle->priv->data = data; +} diff --git a/daemon/gvfsreadhandle.h b/daemon/gvfsreadhandle.h new file mode 100644 index 00000000..760c96d8 --- /dev/null +++ b/daemon/gvfsreadhandle.h @@ -0,0 +1,54 @@ +#ifndef __G_VFS_READ_HANDLE_H__ +#define __G_VFS_READ_HANDLE_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define G_TYPE_VFS_READ_HANDLE (g_vfs_read_handle_get_type ()) +#define G_VFS_READ_HANDLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_READ_HANDLE, GVfsReadHandle)) +#define G_VFS_READ_HANDLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_READ_HANDLE, GVfsReadHandleClass)) +#define G_IS_VFS_READ_HANDLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_READ_HANDLE)) +#define G_IS_VFS_READ_HANDLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_READ_HANDLE)) +#define G_VFS_READ_HANDLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_READ_HANDLE, GVfsReadHandleClass)) + +typedef struct _GVfsReadHandle GVfsReadHandle; +typedef struct _GVfsReadHandleClass GVfsReadHandleClass; +typedef struct _GVfsReadHandlePrivate GVfsReadHandlePrivate; + +struct _GVfsReadHandle +{ + GObject parent_instance; + + GVfsReadHandlePrivate *priv; +}; + +struct _GVfsReadHandleClass +{ + GObjectClass parent_class; + + /* vtable */ + + void (*wants_data) (GVfsReadHandle *handle); +}; + +GType g_vfs_read_handle_get_type (void) G_GNUC_CONST; + +GVfsReadHandle *g_vfs_read_handle_new (GError **error); +int g_vfs_read_handle_get_fd (GVfsReadHandle *read_handle); +int g_vfs_read_handle_get_remote_fd (GVfsReadHandle *read_handle); +void g_vfs_read_handle_close_remote_fd (GVfsReadHandle *read_handle); +void g_vfs_read_handle_set_data (GVfsReadHandle *read_handle, + gpointer data); + +gboolean g_vfs_read_handle_wants_data (GVfsReadHandle *read_handle); +gsize g_vfs_read_handle_get_requested_size (GVfsReadHandle *read_handle); +void g_vfs_read_handle_send_data (GVfsReadHandle *read_handle, + char *data, + gsize length); + +/* TODO: i/o priority? */ + +G_END_DECLS + +#endif /* __G_VFS_READ_HANDLE_H__ */ diff --git a/daemon/gvfsreadrequest.c b/daemon/gvfsreadrequest.c deleted file mode 100644 index eb3ca67a..00000000 --- a/daemon/gvfsreadrequest.c +++ /dev/null @@ -1,111 +0,0 @@ -#include <config.h> - -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <glib.h> -#include <glib-object.h> -#include <glib/gi18n.h> -#include <dbus-gmain.h> -#include <gvfsreadrequest.h> - -G_DEFINE_TYPE (GVfsReadRequest, g_vfs_read_request, G_TYPE_OBJECT); - -enum { - PROP_0, -}; - -struct _GVfsReadRequestPrivate -{ - int fd; - int remote_fd; -}; - -static void -g_vfs_read_request_finalize (GObject *object) -{ - GVfsReadRequest *read_request; - - read_request = G_VFS_READ_REQUEST (object); - - if (read_request->priv->fd != -1) - close (read_request->priv->fd); - - if (read_request->priv->remote_fd != -1) - close (read_request->priv->remote_fd); - - if (G_OBJECT_CLASS (g_vfs_read_request_parent_class)->finalize) - (*G_OBJECT_CLASS (g_vfs_read_request_parent_class)->finalize) (object); -} - -static void -g_vfs_read_request_class_init (GVfsReadRequestClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GVfsReadRequestPrivate)); - - gobject_class->finalize = g_vfs_read_request_finalize; -} - -static void -g_vfs_read_request_init (GVfsReadRequest *request) -{ - request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, - G_TYPE_VFS_READ_REQUEST, - GVfsReadRequestPrivate); - request->priv->fd = -1; - request->priv->remote_fd = -1; -} - -GVfsReadRequest * -g_vfs_read_request_new (GError **error) -{ - GVfsReadRequest *request; - int socket_fds[2]; - int ret; - - ret = socketpair (AF_UNIX, SOCK_STREAM, 0, socket_fds); - if (ret == -1) - { - g_set_error (error, G_FILE_ERROR, - g_file_error_from_errno (errno), - _("Error creating socket pair")); - return NULL; - } - - request = g_object_new (G_TYPE_VFS_READ_REQUEST, NULL); - request->priv->fd = socket_fds[0]; - request->priv->remote_fd = socket_fds[1]; - - return request; -} - -int -g_vfs_read_request_get_fd (GVfsReadRequest *request) -{ - return request->priv->fd; -} - -int - g_vfs_read_request_get_remote_fd (GVfsReadRequest *request) -{ - return request->priv->remote_fd; -} - -void - g_vfs_read_request_close_remote_fd (GVfsReadRequest *request) -{ - close (request->priv->remote_fd); - request->priv->remote_fd = -1; -} - -void -g_vfs_read_request_set_filename (GVfsReadRequest *request, - const char *filename) -{ - g_error ("TODO"); -} diff --git a/daemon/gvfsreadrequest.h b/daemon/gvfsreadrequest.h deleted file mode 100644 index 3187bc97..00000000 --- a/daemon/gvfsreadrequest.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __G_VFS_READ_REQUEST_H__ -#define __G_VFS_READ_REQUEST_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define G_TYPE_VFS_READ_REQUEST (g_vfs_read_request_get_type ()) -#define G_VFS_READ_REQUEST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_READ_REQUEST, GVfsReadRequest)) -#define G_VFS_READ_REQUEST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_READ_REQUEST, GVfsReadRequestClass)) -#define G_IS_VFS_READ_REQUEST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_READ_REQUEST)) -#define G_IS_VFS_READ_REQUEST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_READ_REQUEST)) -#define G_VFS_READ_REQUEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_READ_REQUEST, GVfsReadRequestClass)) - -typedef struct _GVfsReadRequest GVfsReadRequest; -typedef struct _GVfsReadRequestClass GVfsReadRequestClass; -typedef struct _GVfsReadRequestPrivate GVfsReadRequestPrivate; - -struct _GVfsReadRequest -{ - GObject parent_instance; - - GVfsReadRequestPrivate *priv; -}; - -struct _GVfsReadRequestClass -{ - GObjectClass parent_class; - - /* vtable */ - - void (*wants_data) (GVfsReadRequest *request); -}; - -GType g_vfs_read_request_get_type (void) G_GNUC_CONST; - -GVfsReadRequest *g_vfs_read_request_new (GError **error); -int g_vfs_read_request_get_fd (GVfsReadRequest *read_request); -int g_vfs_read_request_get_remote_fd (GVfsReadRequest *read_request); -void g_vfs_read_request_close_remote_fd (GVfsReadRequest *read_request); -void g_vfs_read_request_set_filename (GVfsReadRequest *read_request, - const char *filename); - -gboolean g_vfs_read_request_wants_data (GVfsReadRequest *read_request); -gsize g_vfs_read_request_get_requested_size (GVfsReadRequest *read_request); -void g_vfs_read_request_send_data (GVfsReadRequest *read_request, - char *data, - gsize length); - -/* TODO: i/o priority? */ - -G_END_DECLS - -#endif /* __G_VFS_READ_REQUEST_H__ */ diff --git a/daemon/main.c b/daemon/main.c index 55f7f579..243faec4 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -37,7 +37,9 @@ main (int argc, char *argv[]) GMainLoop *loop; GVfsDaemon *daemon; GVfsDaemonBackendTest *backend; - + + g_thread_init (NULL); + g_type_init (); if (!init_dbus ()) diff --git a/gvfs/gunixfileinputstream.c b/gvfs/gunixfileinputstream.c index 9a7d639f..ea44c2ef 100644 --- a/gvfs/gunixfileinputstream.c +++ b/gvfs/gunixfileinputstream.c @@ -144,6 +144,7 @@ g_unix_file_input_stream_open (GUnixFileInputStream *file, int extra_fd; DBusMessage *message, *reply; DBusMessageIter iter; + guint32 fd_id; if (file->priv->fd != -1) return TRUE; @@ -170,27 +171,18 @@ g_unix_file_input_stream_open (GUnixFileInputStream *file, reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &derror); dbus_message_unref (message); - if (!reply) { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO, - "Error calling ReadFile: %s", - derror.message); + _g_error_from_dbus (&derror, error); dbus_error_free (&derror); return FALSE; } - /* TODO: handle errors created with dbus_message_new_error? - * dbus_message_is_error() ? - */ - if (_g_error_from_dbus_message (reply, error)) - { - dbus_message_unref (reply); - return FALSE; - } - /* No args in reply, only fd */ - + dbus_message_get_args (message, NULL, + DBUS_TYPE_UINT32, &fd_id, + DBUS_TYPE_INVALID); + /* TODO: verify fd id */ file->priv->fd = receive_fd (extra_fd); g_print ("new fd: %d\n", file->priv->fd); return TRUE; diff --git a/gvfs/gvfsunixdbus.c b/gvfs/gvfsunixdbus.c index 47c86473..f027b0c1 100644 --- a/gvfs/gvfsunixdbus.c +++ b/gvfs/gvfsunixdbus.c @@ -49,6 +49,29 @@ free_mount_connection (gpointer data) dbus_connection_unref (conn); } +static void +append_unescaped_dbus_name (GString *s, + const char *escaped, + const char *end) +{ + guchar c; + + while (escaped < end) + { + c = *escaped++; + if (c == '_' && + escaped < end) + { + c = g_ascii_xdigit_value (*escaped++) << 4; + + if (escaped < end) + c |= g_ascii_xdigit_value (*escaped++); + } + g_string_append_c (s, c); + } +} + + /* We use _ for escaping */ #define VALID_INITIAL_BUS_NAME_CHARACTER(c) \ ( ((c) >= 'A' && (c) <= 'Z') || \ @@ -273,48 +296,42 @@ _g_dbus_message_iter_append_filename (DBusMessageIter *iter, const char *filenam return TRUE; } -gboolean -_g_error_from_dbus_message (DBusMessage *message, GError **error) +void +_g_error_from_dbus (DBusError *derror, + GError **error) { - const char *str; - const char *name; - char *m, *gerror_name, *end; + const char *name, *end;; + char *m; + GString *str; GQuark domain; int code; - if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) - return FALSE; - - str = NULL; - dbus_message_get_args (message, NULL, - DBUS_TYPE_STRING, &str, - DBUS_TYPE_INVALID); - - - name = dbus_message_get_error_name (message); - if (g_str_has_prefix (name, "org.glib.GError.")) + if (g_str_has_prefix (derror->name, "org.glib.GError.")) { - gerror_name = g_strdup (name + strlen ("org.glib.GError.")); - end = strchr (gerror_name, '.'); - if (end) - *end++ = 0; - - domain = g_quark_from_string (gerror_name); - g_free (gerror_name); + domain = 0; + code = 0; + name = derror->name + strlen ("org.glib.GError."); + end = strchr (name, '.'); if (end) - code = atoi (end); + { + str = g_string_new (NULL); + append_unescaped_dbus_name (str, name, end); + domain = g_quark_from_string (str->str); + g_string_free (str, TRUE); + + end++; /* skip . */ + if (*end++ == 'c') + code = atoi (end); + } - g_set_error (error, domain, code, str); + g_set_error (error, domain, code, "%s", derror->message); } /* TODO: Special case other types, like DBUS_ERROR_NO_MEMORY etc? */ else { - m = g_strdup_printf ("DBus error %s: %s", name, str); - g_set_error (error, G_FILE_ERROR, - G_FILE_ERROR_IO, m); - + m = g_strdup_printf ("DBus error %s: %s", derror->name, derror->message); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO, "%s", m); + g_free (m); } - - return TRUE; } diff --git a/gvfs/gvfsunixdbus.h b/gvfs/gvfsunixdbus.h index cdfa3540..bfd6649d 100644 --- a/gvfs/gvfsunixdbus.h +++ b/gvfs/gvfsunixdbus.h @@ -11,7 +11,9 @@ DBusConnection *_g_vfs_unix_get_connection_sync (const char *mountpoint, GError **error); gboolean _g_dbus_message_iter_append_filename (DBusMessageIter *iter, const char *filename); -gboolean _g_error_from_dbus_message (DBusMessage *message, +gboolean _g_error_from_dbus_message (DBusMessage *message, + GError **error); +void _g_error_from_dbus (DBusError *derror, GError **error); G_END_DECLS |