diff options
30 files changed, 1041 insertions, 322 deletions
@@ -33,6 +33,8 @@ rename glib lib from gvfs to gio (since it has more than gvfs) G_TYPE_VFS... -> G_VFS_TYPE... +add _hash and _equal to GFile + FUTURE IDEAS: ------------- diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 58c85066..aafefa66 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -7,27 +7,42 @@ INCLUDES = \ -DDBUS_API_SUBJECT_TO_CHANGE \ -DG_DISABLE_DEPRECATED +noinst_LTLIBRARIES=libdaemon.la + libraries = \ $(top_builddir)/gvfs/libgvfs.la \ + libdaemon.la \ $(GLIB_LIBS) $(DBUS_LIBS) + noinst_PROGRAMS = \ gvfs-daemon \ + gvfs-daemon-test \ $(NULL) -gvfs_daemon_SOURCES = \ +libdaemon_la_SOURCES = \ gvfsdaemon.c gvfsdaemon.h \ gvfsbackend.c gvfsbackend.h \ - gvfsbackendtest.c gvfsbackendtest.h \ gvfsreadchannel.c gvfsreadchannel.h \ gvfsdaemonutils.c gvfsdaemonutils.h \ + gvfsmountpoint.c gvfsmountpoint.h \ gvfsjob.c gvfsjob.h \ + gvfsjobsource.c gvfsjobsource.h \ gvfsjobdbus.c gvfsjobdbus.h \ gvfsjobopenforread.c gvfsjobopenforread.h \ gvfsjobread.c gvfsjobread.h \ gvfsjobseekread.c gvfsjobseekread.h \ gvfsjobcloseread.c gvfsjobcloseread.h \ dbus-gmain.h dbus-gmain.c \ + $(NULL) + +gvfs_daemon_SOURCES = \ main.c gvfs_daemon_LDADD = $(libraries) + +gvfs_daemon_test_SOURCES = \ + gvfsbackendtest.c gvfsbackendtest.h \ + test.c + +gvfs_daemon_test_LDADD = $(libraries) diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c index ddf8bce4..ed9216db 100644 --- a/daemon/gvfsbackend.c +++ b/daemon/gvfsbackend.c @@ -9,8 +9,34 @@ #include <dbus/dbus.h> #include <glib/gi18n.h> #include "gvfsbackend.h" - -G_DEFINE_TYPE (GVfsBackend, g_vfs_backend, G_TYPE_OBJECT); +#include "gvfsjobsource.h" +#include "gvfsdaemonprotocol.h" +#include <gvfsjobopenforread.h> + +enum { + PROP_0, + PROP_MOUNTPOINT +}; + +/* TODO: Real P_() */ +#define P_(_x) (_x) + +static void g_vfs_backend_job_source_iface_init (GVfsJobSourceIface *iface); +static void g_vfs_backend_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void g_vfs_backend_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void g_vfs_backend_reset (GVfsJobSource *job_source); + +G_DEFINE_TYPE_WITH_CODE (GVfsBackend, g_vfs_backend, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_VFS_JOB_SOURCE, + g_vfs_backend_job_source_iface_init)) + +volatile gint mountpoint_counter = 0; static void g_vfs_backend_finalize (GObject *object) @@ -19,35 +45,86 @@ g_vfs_backend_finalize (GObject *object) backend = G_VFS_BACKEND (object); + if (backend->mountpoint) + g_vfs_mountpoint_free (backend->mountpoint); + + g_free (backend->mountpoint_path); + if (G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize) (*G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize) (object); } static void +g_vfs_backend_job_source_iface_init (GVfsJobSourceIface *iface) +{ + iface->reset = g_vfs_backend_reset; +} + +static void g_vfs_backend_class_init (GVfsBackendClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = g_vfs_backend_finalize; + gobject_class->set_property = g_vfs_backend_set_property; + gobject_class->get_property = g_vfs_backend_get_property; + + g_object_class_install_property (gobject_class, + PROP_MOUNTPOINT, + g_param_spec_pointer ("mountpoint", + P_("Mountpoint"), + P_("The mountpoint this backend handles."), + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + + } static void g_vfs_backend_init (GVfsBackend *backend) { + int id; + + id = g_atomic_int_exchange_and_add (&mountpoint_counter, 1); + backend->mountpoint_path = g_strdup_printf ("/org/gtk/vfs/mountpoint/%d", id); } -void -g_vfs_backend_set_mountpoint (GVfsBackend *backend, - const char *mountpoint) +static void +g_vfs_backend_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - g_free (backend->mountpoint); - backend->mountpoint = g_strdup (mountpoint); + GVfsBackend *backend = G_VFS_BACKEND (object); + + switch (prop_id) + { + case PROP_MOUNTPOINT: + backend->mountpoint = g_vfs_mountpoint_copy (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } -const char * -g_vfs_backend_get_mountpoint (GVfsBackend *backend) +static void +g_vfs_backend_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - return backend->mountpoint; + GVfsBackend *backend = G_VFS_BACKEND (object); + + switch (prop_id) + { + case PROP_MOUNTPOINT: + g_value_set_pointer (value, backend->mountpoint); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } gboolean @@ -103,3 +180,69 @@ g_vfs_backend_seek_on_read (GVfsBackend *backend, return class->seek_on_read (backend, job, handle, offset, type); } + +static DBusHandlerResult +backend_dbus_handler (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + GVfsBackend *backend = user_data; + GVfsJob *job; + + job = NULL; + + if (dbus_message_is_method_call (message, + G_VFS_DBUS_DAEMON_INTERFACE, + G_VFS_DBUS_OP_OPEN_FOR_READ)) + job = g_vfs_job_open_for_read_new (connection, message, backend); + + if (job) + { + g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (backend), job); + g_object_unref (job); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +signal_mountpoint (GVfsBackend *backend) +{ + DBusMessage *signal; + DBusMessageIter iter; + DBusConnection *bus; + + signal = dbus_message_new_signal (backend->mountpoint_path, + G_VFS_DBUS_MOUNTPOINT_INTERFACE, + G_VFS_DBUS_ANNOUNCE_MOUNTPOINT); + + dbus_message_iter_init_append (signal, &iter); + + g_vfs_mountpoint_to_dbus (backend->mountpoint, &iter); + + bus = dbus_bus_get (DBUS_BUS_SESSION, NULL); + if (bus) + { + dbus_connection_send (bus, signal, NULL); + dbus_connection_unref (bus); + } + + dbus_message_unref (signal); +} + +static void +g_vfs_backend_reset (GVfsJobSource *job_source) +{ + signal_mountpoint (G_VFS_BACKEND (job_source)); +} + +void +g_vfs_backend_register_with_daemon (GVfsBackend *backend, + GVfsDaemon *daemon) +{ + g_vfs_daemon_add_job_source (daemon, G_VFS_JOB_SOURCE (backend)); + g_vfs_daemon_register_path (daemon, backend->mountpoint_path, + backend_dbus_handler, backend); + signal_mountpoint (backend); +} diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h index a0cfc590..1e7c4b46 100644 --- a/daemon/gvfsbackend.h +++ b/daemon/gvfsbackend.h @@ -4,6 +4,8 @@ #include <gvfs/gvfstypes.h> #include <gvfsdaemon.h> #include <gvfsjob.h> +#include <dbus/dbus.h> +#include <gvfsmountpoint.h> G_BEGIN_DECLS @@ -14,15 +16,21 @@ G_BEGIN_DECLS #define G_IS_VFS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_BACKEND)) #define G_VFS_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_BACKEND, GVfsBackendClass)) -/* GVfsBackend defined in gvfsdaemon.h to fix circular defines */ +typedef struct _GVfsBackend GVfsBackend; typedef struct _GVfsBackendClass GVfsBackendClass; +typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead; +typedef struct _GVfsJobSeekRead GVfsJobSeekRead; +typedef struct _GVfsJobCloseRead GVfsJobCloseRead; +typedef struct _GVfsJobRead GVfsJobRead; + typedef gpointer GVfsBackendHandle; struct _GVfsBackend { GObject parent_instance; - char *mountpoint; + GVfsMountpoint *mountpoint; + char *mountpoint_path; }; struct _GVfsBackendClass @@ -59,10 +67,6 @@ struct _GVfsBackendClass GType g_vfs_backend_get_type (void) G_GNUC_CONST; -void g_vfs_backend_set_mountpoint (GVfsBackend *backend, - const char *mountpoint); -const char *g_vfs_backend_get_mountpoint (GVfsBackend *backend); - gboolean g_vfs_backend_open_for_read (GVfsBackend *backend, GVfsJobOpenForRead *job, char *filename); @@ -80,6 +84,9 @@ gboolean g_vfs_backend_seek_on_read (GVfsBackend *backend, goffset offset, GSeekType type); +void g_vfs_backend_register_with_daemon (GVfsBackend *backend, + GVfsDaemon *daemon); + G_END_DECLS #endif /* __G_VFS_BACKEND_H__ */ diff --git a/daemon/gvfsbackendtest.c b/daemon/gvfsbackendtest.c index 3ce5a6c9..877ce74c 100644 --- a/daemon/gvfsbackendtest.c +++ b/daemon/gvfsbackendtest.c @@ -32,15 +32,17 @@ g_vfs_backend_test_finalize (GObject *object) static void g_vfs_backend_test_init (GVfsBackendTest *backend) { - g_vfs_backend_set_mountpoint (G_VFS_BACKEND (backend), "foo://"); } GVfsBackendTest * g_vfs_backend_test_new (void) { GVfsBackendTest *backend; + GVfsMountpoint mountpoint = { "foo", "", "", -1, "" }; + backend = g_object_new (G_TYPE_VFS_BACKEND_TEST, - NULL); + "mountpoint", &mountpoint, + NULL); return backend; } diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c index 2faa364e..2fc08dbf 100644 --- a/daemon/gvfsdaemon.c +++ b/daemon/gvfsdaemon.c @@ -1,9 +1,10 @@ #include <config.h> -#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> +#include <unistd.h> +#include <stdlib.h> #include <glib.h> #include <glib/gi18n.h> @@ -20,16 +21,24 @@ enum { PROP_0, }; +typedef struct { + char *path; + DBusObjectPathMessageFunction callback; + gpointer data; +} RegisteredPath; + struct _GVfsDaemonPrivate { - GHashTable *backends; /* bus_name -> backend */ - - GMutex *lock; /* protects the parts that are accessed by multiple threads */ - - GQueue *pending_jobs; - GQueue *jobs; /* protected by lock */ - guint queued_job_start; /* protected by lock */ - GList *read_channels; /* protected by lock */ + GMutex *lock; + gboolean main_daemon; + + DBusConnection *session_bus; + GHashTable *registered_paths; + GQueue *new_pending_jobs; + GQueue *pending_jobs; /* Only accessed from main thread */ + GQueue *jobs; + guint queued_job_start; + GList *job_sources; }; typedef struct { @@ -52,22 +61,19 @@ static void g_vfs_daemon_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void daemon_unregistered_func (DBusConnection *conn, - gpointer data); static DBusHandlerResult daemon_message_func (DBusConnection *conn, DBusMessage *message, gpointer data); -static DBusHandlerResult daemon_filter_func (DBusConnection *conn, +static DBusHandlerResult peer_to_peer_filter_func (DBusConnection *conn, DBusMessage *message, gpointer data); -static void start_or_queue_job (GVfsDaemon *daemon, - GVfsJob *job); -static DBusObjectPathVTable daemon_vtable = { - daemon_unregistered_func, - daemon_message_func, - NULL -}; +static void +registered_path_free (RegisteredPath *data) +{ + g_free (data->path); + g_free (data); +} static void g_vfs_daemon_finalize (GObject *object) @@ -80,8 +86,9 @@ g_vfs_daemon_finalize (GObject *object) g_assert (daemon->priv->pending_jobs->head == NULL); g_queue_free (daemon->priv->jobs); g_queue_free (daemon->priv->pending_jobs); + g_queue_free (daemon->priv->new_pending_jobs); - g_hash_table_destroy (daemon->priv->backends); + g_hash_table_destroy (daemon->priv->registered_paths); g_mutex_free (daemon->priv->lock); if (G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize) @@ -107,12 +114,19 @@ g_vfs_daemon_init (GVfsDaemon *daemon) G_TYPE_VFS_DAEMON, GVfsDaemonPrivate); daemon->priv->lock = g_mutex_new (); + daemon->priv->session_bus = dbus_bus_get (DBUS_BUS_SESSION, NULL); daemon->priv->jobs = g_queue_new (); daemon->priv->pending_jobs = g_queue_new (); - daemon->priv->backends = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); + daemon->priv->new_pending_jobs = g_queue_new (); + daemon->priv->registered_paths = + g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, + (GDestroyNotify)registered_path_free); + + if (!dbus_connection_add_filter (daemon->priv->session_bus, + daemon_message_func, daemon, NULL)) + g_error ("Not enough memory to add filter"); } static void @@ -152,55 +166,169 @@ g_vfs_daemon_get_property (GObject *object, } GVfsDaemon * -g_vfs_daemon_new (void) +g_vfs_daemon_new (gboolean main_daemon, gboolean replace) { GVfsDaemon *daemon; + DBusConnection *conn; + DBusError error; + unsigned int flags; + int ret; + g_print ("main_daemon: %d, replace %d\n", main_daemon, replace); + + dbus_error_init (&error); + conn = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (!conn) + { + g_printerr ("Failed to connect to the D-BUS daemon: %s\n", + error.message); + + dbus_error_free (&error); + return NULL; + } + + dbus_bus_add_match (conn, + "sender='org.freedesktop.DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'", + &error); + if (dbus_error_is_set (&error)) + { + g_printerr ("Failed to connect to add dbus match: %s\n", + error.message); + dbus_error_free (&error); + return NULL; + } + + dbus_connection_setup_with_g_main (conn, NULL); + daemon = g_object_new (G_TYPE_VFS_DAEMON, NULL); + daemon->priv->main_daemon = main_daemon; + + /* Request name only after we've installed the message filter */ + if (main_daemon) + { + flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT | DBUS_NAME_FLAG_DO_NOT_QUEUE; + if (replace) + flags |= DBUS_NAME_FLAG_REPLACE_EXISTING; + + g_print ("requesting name\n"); + ret = dbus_bus_request_name (conn, G_VFS_DBUS_DAEMON_NAME, flags, &error); + if (ret == -1) + { + g_printerr ("Failed to acquire daemon name: %s", error.message); + dbus_error_free (&error); + + g_object_unref (daemon); + daemon = NULL; + } + else if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS) + { + g_printerr ("VFS daemon already running, exiting.\n"); + g_object_unref (daemon); + daemon = NULL; + } + else if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + g_printerr ("Not primary owner of the service, exiting.\n"); + g_object_unref (daemon); + daemon = NULL; + } + } + + dbus_connection_unref (conn); + return daemon; } -gboolean -g_vfs_daemon_add_backend (GVfsDaemon *daemon, - GVfsBackend *backend) +static void +job_source_new_job_callback (GVfsJobSource *job_source, + GVfsJob *job, + GVfsDaemon *daemon) { - DBusConnection *conn; - const char *mountpoint; - char *bus_name; - int ret; - DBusError error; + g_vfs_daemon_queue_job (daemon, job); +} - mountpoint = g_vfs_backend_get_mountpoint (backend); +static void +job_source_closed_callback (GVfsJobSource *job_source, + GVfsDaemon *daemon) +{ + g_mutex_lock (daemon->priv->lock); + + daemon->priv->job_sources = g_list_remove (daemon->priv->job_sources, + job_source); + + g_signal_handlers_disconnect_by_func (job_source, + (GCallback)job_source_new_job_callback, + daemon); + g_signal_handlers_disconnect_by_func (job_source, + (GCallback)job_source_closed_callback, + daemon); - g_assert (g_hash_table_lookup (daemon->priv->backends, mountpoint) == NULL); + g_object_unref (job_source); + + g_mutex_unlock (daemon->priv->lock); +} - conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); - if (conn == NULL) +void +g_vfs_daemon_add_job_source (GVfsDaemon *daemon, + GVfsJobSource *job_source) +{ + g_print ("Added new job source %p (%s)\n", job_source, g_type_name_from_instance ((gpointer)job_source)); + + g_mutex_lock (daemon->priv->lock); + + g_object_ref (job_source); + daemon->priv->job_sources = g_list_append (daemon->priv->job_sources, + job_source); + g_signal_connect (job_source, "new_job", + (GCallback)job_source_new_job_callback, daemon); + g_signal_connect (job_source, "closed", + (GCallback)job_source_closed_callback, daemon); + + g_mutex_unlock (daemon->priv->lock); +} + +gboolean +g_vfs_daemon_register_path (GVfsDaemon *daemon, + const char *path, + DBusObjectPathMessageFunction callback, + gpointer user_data) +{ + RegisteredPath *data; + + if (g_hash_table_lookup (daemon->priv->registered_paths, path) != NULL) return FALSE; - bus_name = _g_dbus_bus_name_from_mountpoint (mountpoint); - g_print ("bus_name: %s, mountpoint: %s\n", bus_name, mountpoint); - dbus_error_init (&error); - ret = dbus_bus_request_name (conn, bus_name, 0, &error); - if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) - { - g_printerr ("Failed to acquire vfs-daemon service: %s", error.message); - dbus_error_free (&error); - return FALSE; - } + data = g_new0 (RegisteredPath, 1); + data->path = g_strdup (path); + data->callback = callback; + data->data = user_data; - if (!dbus_connection_register_object_path (conn, - G_VFS_DBUS_DAEMON_PATH, - &daemon_vtable, - daemon)) - g_error ("Failed to register object with D-BUS (oom).\n"); + g_hash_table_insert (daemon->priv->registered_paths, data->path, data); - g_hash_table_insert (daemon->priv->backends, - bus_name, - g_object_ref (backend)); return TRUE; } +static void +g_queue_move_items (GQueue *to, GQueue *from) +{ + GList *ignore; + if (from->head != NULL) + { + if (to->head == NULL) + to->head = from->head; + else + ignore = g_list_concat (to->tail, from->head); + to->tail = from->tail; + to->length += from->length; + + from->head = NULL; + from->tail = NULL; + from->length = 0; + } +} + static gboolean start_jobs_at_idle (gpointer data) { @@ -210,6 +338,8 @@ start_jobs_at_idle (gpointer data) g_mutex_lock (daemon->priv->lock); daemon->priv->queued_job_start = 0; + g_queue_move_items (daemon->priv->pending_jobs, + daemon->priv->new_pending_jobs); g_mutex_unlock (daemon->priv->lock); l = daemon->priv->pending_jobs->head; @@ -227,35 +357,13 @@ start_jobs_at_idle (gpointer data) 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 -handle_new_job_callback (GVfsReadChannel *channel, - GVfsJob *job, +job_new_source_callback (GVfsJob *job, + GVfsJobSource *job_source, GVfsDaemon *daemon) { - g_print ("handle_new_job_callback() job=%p daemon=%p\n", job, daemon); - g_object_ref (job); - start_or_queue_job (daemon, job); -} - -static void -handle_read_channel_closed_callback (GVfsReadChannel *channel, - GVfsDaemon *daemon) -{ - g_mutex_lock (daemon->priv->lock); - - daemon->priv->read_channels = g_list_remove (daemon->priv->read_channels, channel); - g_signal_handlers_disconnect_by_func (channel, (GCallback)handle_new_job_callback, daemon); - g_object_unref (channel); - - g_mutex_unlock (daemon->priv->lock); + g_vfs_daemon_add_job_source (daemon, job_source); } /* NOTE: Might be emitted on a thread */ @@ -263,50 +371,47 @@ static void job_finished_callback (GVfsJob *job, GVfsDaemon *daemon) { + + g_signal_handlers_disconnect_by_func (job, + (GCallback)job_new_source_callback, + daemon); + g_signal_handlers_disconnect_by_func (job, + (GCallback)job_finished_callback, + daemon); + g_mutex_lock (daemon->priv->lock); g_queue_remove (daemon->priv->jobs, job); - queue_start_jobs_at_idle (daemon); - - if (G_IS_VFS_JOB_OPEN_FOR_READ (job)) - { - GVfsJobOpenForRead *open_job = G_VFS_JOB_OPEN_FOR_READ (job); - GVfsReadChannel *channel; - - channel = g_vfs_job_open_for_read_steal_channel (open_job); - - if (channel) - { - g_print ("Got new read channel %p for daemon %p\n", channel, daemon); - daemon->priv->read_channels = g_list_append (daemon->priv->read_channels, - channel); - g_signal_connect (channel, "new_job", (GCallback)handle_new_job_callback, daemon); - g_signal_connect (channel, "closed", (GCallback)handle_read_channel_closed_callback, daemon); - } - } - + if (daemon->priv->queued_job_start == 0) + daemon->priv->queued_job_start = g_idle_add (start_jobs_at_idle, daemon); + g_mutex_unlock (daemon->priv->lock); g_object_unref (job); } -static void -start_or_queue_job (GVfsDaemon *daemon, - GVfsJob *job) +void +g_vfs_daemon_queue_job (GVfsDaemon *daemon, + GVfsJob *job) { - g_assert (job->backend != NULL); + g_print ("Queued new job %p (%s)\n", job, g_type_name_from_instance ((gpointer)job)); + + g_object_ref (job); + g_signal_connect (job, "finished", (GCallback)job_finished_callback, daemon); + g_signal_connect (job, "new_source", (GCallback)job_new_source_callback, daemon); 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); + g_mutex_lock (daemon->priv->lock); + g_queue_push_tail (daemon->priv->new_pending_jobs, job); + g_mutex_unlock (daemon->priv->lock); } } @@ -328,7 +433,7 @@ new_connection_data_free (void *memory) static void daemon_peer_connection_setup (GVfsDaemon *daemon, - DBusConnection *dbus_conn, + DBusConnection *dbus_conn, NewConnectionData *data) { /* We wait until we have the extra fd */ @@ -344,11 +449,8 @@ daemon_peer_connection_setup (GVfsDaemon *daemon, } dbus_connection_setup_with_g_main (dbus_conn, NULL); - if (!dbus_connection_add_filter (dbus_conn, daemon_filter_func, daemon, NULL) || - !dbus_connection_register_object_path (dbus_conn, - G_VFS_DBUS_DAEMON_PATH, - &daemon_vtable, - daemon)) + if (!dbus_connection_add_filter (dbus_conn, peer_to_peer_filter_func, daemon, NULL) || + !dbus_connection_add_filter (dbus_conn, daemon_message_func, daemon, NULL)) { g_warning (_("Failed to accept client: %s"), _("object registration failed")); dbus_connection_unref (dbus_conn); @@ -598,20 +700,6 @@ accept_new_fd_client (GIOChannel *channel, } static void -append_mountpoint_cb (gpointer key, - gpointer value, - gpointer user_data) -{ - DBusMessageIter *array_iter = user_data; - GVfsBackend *backend = value; - char *mountpoint = backend->mountpoint; - - if (!dbus_message_iter_append_basic (array_iter, - DBUS_TYPE_STRING, &mountpoint)) - g_error ("Can't allocate dbus message"); -} - -static void daemon_handle_get_connection (DBusConnection *conn, DBusMessage *message, GVfsDaemon *daemon) @@ -625,7 +713,6 @@ daemon_handle_get_connection (DBusConnection *conn, GIOChannel *channel; char *socket_dir; int fd; - DBusMessageIter iter, array_iter; generate_addresses (&address1, &address2, &socket_dir); @@ -679,21 +766,6 @@ daemon_handle_get_connection (DBusConnection *conn, DBUS_TYPE_STRING, &address2, DBUS_TYPE_INVALID)) g_error ("Can't allocate dbus message\n"); - - dbus_message_iter_init_append (reply, &iter); - - if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, - &array_iter)) - g_error ("Can't allocate dbus message\n"); - - - g_hash_table_foreach (daemon->priv->backends, - append_mountpoint_cb, - &array_iter); - - if (!dbus_message_iter_close_container (&iter, &array_iter)) - g_error ("Can't allocate dbus message\n"); dbus_connection_send (conn, reply, NULL); @@ -715,22 +787,51 @@ daemon_handle_get_connection (DBusConnection *conn, } } - -static void -daemon_unregistered_func (DBusConnection *conn, - gpointer data) -{ -} - static DBusHandlerResult daemon_message_func (DBusConnection *conn, DBusMessage *message, gpointer data) { GVfsDaemon *daemon = data; - GVfsBackend *backend; - const char *dest; GVfsJob *job; + RegisteredPath *registered_path; + + if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) + { + char *name, *from, *to; + if (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &from, + DBUS_TYPE_STRING, &to, + DBUS_TYPE_INVALID)) + { + const char *my_name = dbus_bus_get_unique_name (conn); + + g_print ("NameOwnerChanged %s %s->%s (my name: %s)\n", name, from, to, my_name); + + if (strcmp (name, G_VFS_DBUS_DAEMON_NAME) == 0) + { + /* Someone else got the name (i.e. someone used --replace), exit */ + if (daemon->priv->main_daemon && + strcmp (to, my_name) != 0) + exit (1); + + if (*to != 0) + { + GList *l; + + /* New owner, tell all backends to re-register */ + g_mutex_lock (daemon->priv->lock); + for (l = daemon->priv->job_sources; l != NULL; l = l->next) + { + GVfsJobSource *source = l->data; + g_vfs_job_source_reset (source); + } + g_mutex_unlock (daemon->priv->lock); + } + } + } + } job = NULL; if (dbus_message_is_method_call (message, @@ -780,32 +881,21 @@ daemon_message_func (DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - - backend = NULL; - dest = dbus_message_get_destination (message); - if (dest != NULL) - backend = g_hash_table_lookup (daemon->priv->backends, - dest); - if (backend == NULL) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (dbus_message_is_method_call (message, - G_VFS_DBUS_DAEMON_INTERFACE, - G_VFS_DBUS_OP_OPEN_FOR_READ)) - job = g_vfs_job_open_for_read_new (conn, message, backend); + registered_path = g_hash_table_lookup (daemon->priv->registered_paths, + dbus_message_get_path (message)); + if (registered_path) + return registered_path->callback (conn, message, registered_path->data); else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (job) - start_or_queue_job (daemon, job); - - return DBUS_HANDLER_RESULT_HANDLED; } + +/* Only called for peer-to-peer connections */ static DBusHandlerResult -daemon_filter_func (DBusConnection *conn, - DBusMessage *message, - gpointer data) +peer_to_peer_filter_func (DBusConnection *conn, + DBusMessage *message, + gpointer data) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, diff --git a/daemon/gvfsdaemon.h b/daemon/gvfsdaemon.h index 7440d381..405f2332 100644 --- a/daemon/gvfsdaemon.h +++ b/daemon/gvfsdaemon.h @@ -2,6 +2,8 @@ #define __G_VFS_DAEMON_H__ #include <glib-object.h> +#include <gvfsjobsource.h> +#include <dbus/dbus.h> G_BEGIN_DECLS @@ -16,9 +18,6 @@ typedef struct _GVfsDaemon GVfsDaemon; typedef struct _GVfsDaemonClass GVfsDaemonClass; typedef struct _GVfsDaemonPrivate GVfsDaemonPrivate; -/* Placed here to fix circular ref problems in headers */ -typedef struct _GVfsBackend GVfsBackend; - struct _GVfsDaemon { GObject parent_instance; @@ -36,9 +35,16 @@ struct _GVfsDaemonClass GType g_vfs_daemon_get_type (void) G_GNUC_CONST; -GVfsDaemon *g_vfs_daemon_new (void); -gboolean g_vfs_daemon_add_backend (GVfsDaemon *daemon, - GVfsBackend *backend); +GVfsDaemon *g_vfs_daemon_new (gboolean main_daemon, + gboolean replace); +void g_vfs_daemon_add_job_source (GVfsDaemon *daemon, + GVfsJobSource *job_source); +void g_vfs_daemon_queue_job (GVfsDaemon *daemon, + GVfsJob *job); +gboolean g_vfs_daemon_register_path (GVfsDaemon *daemon, + const char *path, + DBusObjectPathMessageFunction callback, + gpointer user_data); G_END_DECLS diff --git a/daemon/gvfsdaemonprotocol.h b/daemon/gvfsdaemonprotocol.h index ef3879a8..a265c5fb 100644 --- a/daemon/gvfsdaemonprotocol.h +++ b/daemon/gvfsdaemonprotocol.h @@ -3,6 +3,11 @@ G_BEGIN_DECLS +#define G_VFS_DBUS_DAEMON_NAME "org.gtk.vfs.Daemon" + +#define G_VFS_DBUS_MOUNTPOINT_INTERFACE "org.gtk.vfs.Mountpoint" +#define G_VFS_DBUS_ANNOUNCE_MOUNTPOINT "AnnounceMountpoint" + #define G_VFS_DBUS_MOUNTPOINT_NAME "org.gtk.vfs.mount." #define G_VFS_DBUS_ERROR_SOCKET_FAILED "org.gtk.vfs.Error.SocketFailed" diff --git a/daemon/gvfsdaemonutils.c b/daemon/gvfsdaemonutils.c index 68dd5825..d8b62853 100644 --- a/daemon/gvfsdaemonutils.c +++ b/daemon/gvfsdaemonutils.c @@ -265,3 +265,24 @@ g_error_to_daemon_reply (GError *error, guint32 seq_nr, gsize *len_out) return buffer; } +gboolean +_g_dbus_message_iter_append_filename (DBusMessageIter *iter, const char *filename) +{ + DBusMessageIter array; + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array)) + return FALSE; + + if (!dbus_message_iter_append_fixed_array (&array, + DBUS_TYPE_BYTE, + &filename, strlen (filename))) + return FALSE; + + if (!dbus_message_iter_close_container (iter, &array)) + return FALSE; + + return TRUE; +} diff --git a/daemon/gvfsdaemonutils.h b/daemon/gvfsdaemonutils.h index 16b27bd9..507d3e28 100644 --- a/daemon/gvfsdaemonutils.h +++ b/daemon/gvfsdaemonutils.h @@ -6,18 +6,20 @@ 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); -char * g_error_to_daemon_reply (GError *error, - guint32 seq_nr, - gsize *len_out); -char * _g_dbus_bus_name_from_mountpoint (const char *mountpoint); +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); +char * g_error_to_daemon_reply (GError *error, + guint32 seq_nr, + gsize *len_out); +char * _g_dbus_bus_name_from_mountpoint (const char *mountpoint); +gboolean _g_dbus_message_iter_append_filename (DBusMessageIter *iter, + const char *filename); G_END_DECLS diff --git a/daemon/gvfsjob.c b/daemon/gvfsjob.c index 6207773b..36db2578 100644 --- a/daemon/gvfsjob.c +++ b/daemon/gvfsjob.c @@ -9,7 +9,6 @@ #include <dbus/dbus.h> #include <glib/gi18n.h> #include "gvfsjob.h" -#include "gvfsbackend.h" G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_OBJECT); @@ -18,7 +17,6 @@ G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_OBJECT); enum { PROP_0, - PROP_BACKEND, }; enum { @@ -28,6 +26,11 @@ enum { LAST_SIGNAL }; +struct _GVfsJobPrivate +{ + int dummy; +}; + static guint signals[LAST_SIGNAL] = { 0 }; static void g_vfs_job_get_property (GObject *object, @@ -57,6 +60,8 @@ static void g_vfs_job_class_init (GVfsJobClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GVfsJobPrivate)); gobject_class->finalize = g_vfs_job_finalize; gobject_class->set_property = g_vfs_job_set_property; @@ -86,20 +91,13 @@ g_vfs_job_class_init (GVfsJobClass *klass) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_object_class_install_property (gobject_class, - PROP_BACKEND, - g_param_spec_object ("backend", - P_("VFS Backend"), - P_("The implementation for this job operartion."), - G_TYPE_VFS_BACKEND, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); } static void g_vfs_job_init (GVfsJob *job) { + job->priv = G_TYPE_INSTANCE_GET_PRIVATE (job, G_TYPE_VFS_JOB, GVfsJobPrivate); + } static void @@ -108,13 +106,8 @@ g_vfs_job_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - GVfsJob *job = G_VFS_JOB (object); - switch (prop_id) { - case PROP_BACKEND: - job->backend = g_value_get_object (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -127,13 +120,8 @@ g_vfs_job_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GVfsJob *job = G_VFS_JOB (object); - switch (prop_id) { - case PROP_BACKEND: - g_value_set_object (value, job->backend); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/daemon/gvfsjob.h b/daemon/gvfsjob.h index b9cc4702..6eb1fbfc 100644 --- a/daemon/gvfsjob.h +++ b/daemon/gvfsjob.h @@ -2,7 +2,6 @@ #define __G_VFS_JOB_H__ #include <glib-object.h> -#include <gvfsdaemon.h> G_BEGIN_DECLS @@ -13,26 +12,26 @@ 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 _GVfsJobPrivate GVfsJobPrivate; +typedef struct _GVfsJobClass GVfsJobClass; -/* Define these here to avoid circular includes */ -typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead; -typedef struct _GVfsJobCloseRead GVfsJobCloseRead; -typedef struct _GVfsJobRead GVfsJobRead; -typedef struct _GVfsJobSeekRead GVfsJobSeekRead; +/* Defined here to avoid circular includes */ +typedef struct _GVfsJobSource GVfsJobSource; struct _GVfsJob { GObject parent_instance; - - GVfsBackend *backend; + + /* TODO: Move stuff to private */ gpointer backend_data; guint failed : 1; guint cancelled : 1; guint sending_reply : 1; guint finished : 1; GError *error; + + GVfsJobPrivate *priv; }; struct _GVfsJobClass @@ -42,6 +41,8 @@ struct _GVfsJobClass /* signals */ void (*cancelled) (GVfsJob *job); void (*send_reply) (GVfsJob *job); + void (*new_source) (GVfsJob *job, + GVfsJobSource *job_source); void (*finished) (GVfsJob *job); /* vtable */ diff --git a/daemon/gvfsjobcloseread.c b/daemon/gvfsjobcloseread.c index 28aeddc2..4ea7904a 100644 --- a/daemon/gvfsjobcloseread.c +++ b/daemon/gvfsjobcloseread.c @@ -53,10 +53,10 @@ g_vfs_job_close_read_new (GVfsReadChannel *channel, GVfsJobCloseRead *job; job = g_object_new (G_TYPE_VFS_JOB_CLOSE_READ, - "backend", backend, NULL); job->channel = g_object_ref (channel); + job->backend = backend; job->handle = handle; return G_VFS_JOB (job); @@ -81,7 +81,7 @@ start (GVfsJob *job) { GVfsJobCloseRead *op_job = G_VFS_JOB_CLOSE_READ (job); - return g_vfs_backend_close_read (job->backend, + return g_vfs_backend_close_read (op_job->backend, op_job, op_job->handle); } diff --git a/daemon/gvfsjobcloseread.h b/daemon/gvfsjobcloseread.h index 5333c006..f7725593 100644 --- a/daemon/gvfsjobcloseread.h +++ b/daemon/gvfsjobcloseread.h @@ -14,7 +14,6 @@ G_BEGIN_DECLS #define G_IS_VFS_JOB_CLOSE_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_CLOSE_READ)) #define G_VFS_JOB_CLOSE_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_CLOSE_READ, GVfsJobCloseReadClass)) -/* GVfsJobCloseRead declared in gvfsjob.h */ typedef struct _GVfsJobCloseReadClass GVfsJobCloseReadClass; struct _GVfsJobCloseRead @@ -22,6 +21,7 @@ struct _GVfsJobCloseRead GVfsJob parent_instance; GVfsReadChannel *channel; + GVfsBackend *backend; GVfsBackendHandle handle; }; diff --git a/daemon/gvfsjobdbus.c b/daemon/gvfsjobdbus.c new file mode 100644 index 00000000..d693f346 --- /dev/null +++ b/daemon/gvfsjobdbus.c @@ -0,0 +1,162 @@ +#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 "gvfsjobdbus.h" +#include "gvfsdaemonutils.h" + +G_DEFINE_TYPE (GVfsJobDBus, g_vfs_job_dbus, G_TYPE_VFS_JOB); + +/* TODO: Real P_() */ +#define P_(_x) (_x) + +enum { + PROP_0, + PROP_MESSAGE, + PROP_CONNECTION, +}; + +static void send_reply (GVfsJob *job); +static void g_vfs_job_dbus_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void g_vfs_job_dbus_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static void +g_vfs_job_dbus_finalize (GObject *object) +{ + GVfsJobDBus *job; + + job = G_VFS_JOB_DBUS (object); + + if (job->message) + dbus_message_unref (job->message); + + if (job->connection) + dbus_connection_unref (job->connection); + + if (G_OBJECT_CLASS (g_vfs_job_dbus_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_job_dbus_parent_class)->finalize) (object); +} + +static void +g_vfs_job_dbus_class_init (GVfsJobDBusClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass); + + gobject_class->finalize = g_vfs_job_dbus_finalize; + gobject_class->set_property = g_vfs_job_dbus_set_property; + gobject_class->get_property = g_vfs_job_dbus_get_property; + + job_class->send_reply = send_reply; + + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + g_param_spec_pointer ("connection", + P_("VFS Backend"), + P_("The implementation for this job operartion."), + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + g_object_class_install_property (gobject_class, + PROP_MESSAGE, + g_param_spec_pointer ("message", + P_("VFS Backend"), + P_("The implementation for this job operartion."), + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); +} + +static void +g_vfs_job_dbus_init (GVfsJobDBus *job) +{ +} + +static void +g_vfs_job_dbus_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GVfsJobDBus *job = G_VFS_JOB_DBUS (object); + + switch (prop_id) + { + case PROP_MESSAGE: + job->message = dbus_message_ref (g_value_get_pointer (value)); + break; + case PROP_CONNECTION: + job->connection = dbus_connection_ref (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_vfs_job_dbus_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GVfsJobDBus *job = G_VFS_JOB_DBUS (object); + + switch (prop_id) + { + case PROP_MESSAGE: + g_value_set_pointer (value, job->message); + break; + case PROP_CONNECTION: + g_value_set_pointer (value, job->connection); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* Might be called on an i/o thread */ +static void +send_reply (GVfsJob *job) +{ + GVfsJobDBus *dbus_job = G_VFS_JOB_DBUS (job); + DBusMessage *reply; + GVfsJobDBusClass *class; + + g_print ("send_reply, failed=%d (%s)\n", job->failed, job->failed?job->error->message:""); + + class = G_VFS_JOB_DBUS_GET_CLASS (job); + + if (job->failed) + reply = dbus_message_new_error_from_gerror (dbus_job->message, job->error); + else + reply = class->create_reply (job, dbus_job->connection, dbus_job->message); + + g_assert (reply != NULL); + + /* Queues reply (threadsafely), actually sends it in mainloop */ + dbus_connection_send (dbus_job->connection, reply, NULL); + dbus_message_unref (reply); + + g_vfs_job_emit_finished (job); +} + +gboolean +g_vfs_job_dbus_is_serial (GVfsJobDBus *job_dbus, + DBusConnection *connection, + dbus_uint32_t serial) +{ + return job_dbus->connection == connection && + dbus_message_get_serial (job_dbus->message) == serial; +} diff --git a/daemon/gvfsjobdbus.h b/daemon/gvfsjobdbus.h new file mode 100644 index 00000000..78d68d84 --- /dev/null +++ b/daemon/gvfsjobdbus.h @@ -0,0 +1,46 @@ +#ifndef __G_VFS_JOB_DBUS_H__ +#define __G_VFS_JOB_DBUS_H__ + +#include <dbus/dbus.h> +#include <gvfsjob.h> +#include <gvfsbackend.h> + +G_BEGIN_DECLS + +#define G_TYPE_VFS_JOB_DBUS (g_vfs_job_dbus_get_type ()) +#define G_VFS_JOB_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_JOB_DBUS, GVfsJobDBus)) +#define G_VFS_JOB_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_JOB_DBUS, GVfsJobDBusClass)) +#define G_IS_VFS_JOB_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_JOB_DBUS)) +#define G_IS_VFS_JOB_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_DBUS)) +#define G_VFS_JOB_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_DBUS, GVfsJobDBusClass)) + +typedef struct _GVfsJobDBus GVfsJobDBus; +typedef struct _GVfsJobDBusClass GVfsJobDBusClass; + +struct _GVfsJobDBus +{ + GVfsJob parent_instance; + + DBusConnection *connection; + DBusMessage *message; +}; + +struct _GVfsJobDBusClass +{ + GVfsJobClass parent_class; + + /* Might be called on an i/o thread */ + DBusMessage * (*create_reply) (GVfsJob *job, + DBusConnection *connection, + DBusMessage *message); +}; + +GType g_vfs_job_dbus_get_type (void) G_GNUC_CONST; + +gboolean g_vfs_job_dbus_is_serial (GVfsJobDBus *job_dbus, + DBusConnection *connection, + dbus_uint32_t serial); + +G_END_DECLS + +#endif /* __G_VFS_JOB_DBUS_H__ */ diff --git a/daemon/gvfsjobopenforread.c b/daemon/gvfsjobopenforread.c index 6eec8d9f..baff8aea 100644 --- a/daemon/gvfsjobopenforread.c +++ b/daemon/gvfsjobopenforread.c @@ -81,12 +81,12 @@ g_vfs_job_open_for_read_new (DBusConnection *connection, } job = g_object_new (G_TYPE_VFS_JOB_OPEN_FOR_READ, - "backend", backend, "message", message, "connection", connection, NULL); job->filename = g_strndup (path_data, path_len); + job->backend = backend; return G_VFS_JOB (job); } @@ -96,7 +96,7 @@ start (GVfsJob *job) { GVfsJobOpenForRead *op_job = G_VFS_JOB_OPEN_FOR_READ (job); - return g_vfs_backend_open_for_read (job->backend, + return g_vfs_backend_open_for_read (op_job->backend, op_job, op_job->filename); } @@ -133,7 +133,7 @@ create_reply (GVfsJob *job, g_assert (open_job->backend_handle != NULL); error = NULL; - channel = g_vfs_read_channel_new (job->backend, &error); + channel = g_vfs_read_channel_new (open_job->backend, &error); if (channel == NULL) { reply = dbus_message_new_error_from_gerror (message, error); diff --git a/daemon/gvfsjobopenforread.h b/daemon/gvfsjobopenforread.h index b301bb5c..4be12bcc 100644 --- a/daemon/gvfsjobopenforread.h +++ b/daemon/gvfsjobopenforread.h @@ -15,7 +15,6 @@ G_BEGIN_DECLS #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 @@ -23,6 +22,7 @@ struct _GVfsJobOpenForRead GVfsJobDBus parent_instance; char *filename; + GVfsBackend *backend; GVfsBackendHandle backend_handle; gboolean can_seek; GVfsReadChannel *read_channel; diff --git a/daemon/gvfsjobread.c b/daemon/gvfsjobread.c index 84cbe277..e8f45df6 100644 --- a/daemon/gvfsjobread.c +++ b/daemon/gvfsjobread.c @@ -56,9 +56,9 @@ g_vfs_job_read_new (GVfsReadChannel *channel, GVfsJobRead *job; job = g_object_new (G_TYPE_VFS_JOB_READ, - "backend", backend, NULL); - + + job->backend = backend; job->channel = g_object_ref (channel); job->handle = handle; job->buffer = g_malloc (bytes_requested); @@ -89,7 +89,7 @@ start (GVfsJob *job) { GVfsJobRead *op_job = G_VFS_JOB_READ (job); - return g_vfs_backend_read (job->backend, + return g_vfs_backend_read (op_job->backend, op_job, op_job->handle, op_job->buffer, diff --git a/daemon/gvfsjobread.h b/daemon/gvfsjobread.h index f7cda3e8..ea084428 100644 --- a/daemon/gvfsjobread.h +++ b/daemon/gvfsjobread.h @@ -14,7 +14,6 @@ G_BEGIN_DECLS #define G_IS_VFS_JOB_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_READ)) #define G_VFS_JOB_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_READ, GVfsJobReadClass)) -/* GVfsJobRead declared in gvfsjob.h */ typedef struct _GVfsJobReadClass GVfsJobReadClass; struct _GVfsJobRead @@ -22,6 +21,7 @@ struct _GVfsJobRead GVfsJob parent_instance; GVfsReadChannel *channel; + GVfsBackend *backend; GVfsBackendHandle handle; gsize bytes_requested; char *buffer; diff --git a/daemon/gvfsjobseekread.c b/daemon/gvfsjobseekread.c index d3678b31..0e898cf1 100644 --- a/daemon/gvfsjobseekread.c +++ b/daemon/gvfsjobseekread.c @@ -55,9 +55,9 @@ g_vfs_job_seek_read_new (GVfsReadChannel *channel, GVfsJobSeekRead *job; job = g_object_new (G_TYPE_VFS_JOB_SEEK_READ, - "backend", backend, NULL); - + + job->backend = backend; job->channel = g_object_ref (channel); job->handle = handle; job->requested_offset = offset; @@ -88,7 +88,7 @@ start (GVfsJob *job) { GVfsJobSeekRead *op_job = G_VFS_JOB_SEEK_READ (job); - return g_vfs_backend_seek_on_read (job->backend, + return g_vfs_backend_seek_on_read (op_job->backend, op_job, op_job->handle, op_job->requested_offset, diff --git a/daemon/gvfsjobseekread.h b/daemon/gvfsjobseekread.h index be11be53..15f5bc64 100644 --- a/daemon/gvfsjobseekread.h +++ b/daemon/gvfsjobseekread.h @@ -14,7 +14,6 @@ G_BEGIN_DECLS #define G_IS_VFS_JOB_SEEK_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_SEEK_READ)) #define G_VFS_JOB_SEEK_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_SEEK_READ, GVfsJobSeekReadClass)) -/* GVfsJobSeekRead declared in gvfsjob.h */ typedef struct _GVfsJobSeekReadClass GVfsJobSeekReadClass; struct _GVfsJobSeekRead @@ -22,6 +21,7 @@ struct _GVfsJobSeekRead GVfsJob parent_instance; GVfsReadChannel *channel; + GVfsBackend *backend; GVfsBackendHandle handle; GSeekType seek_type; goffset requested_offset; diff --git a/daemon/gvfsjobsource.c b/daemon/gvfsjobsource.c new file mode 100644 index 00000000..86fef8ea --- /dev/null +++ b/daemon/gvfsjobsource.c @@ -0,0 +1,108 @@ +#include <config.h> +#include "gvfsjobsource.h" + +static void g_vfs_job_source_base_init (gpointer g_class); + +enum { + NEW_JOB, + CLOSED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +GType +g_vfs_job_source_get_type (void) +{ + static GType vfs_job_source_type = 0; + + if (! vfs_job_source_type) + { + static const GTypeInfo vfs_job_source_info = + { + sizeof (GVfsJobSourceIface), /* class_size */ + g_vfs_job_source_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + vfs_job_source_type = + g_type_register_static (G_TYPE_INTERFACE, "GVfsJobSource", + &vfs_job_source_info, 0); + + g_type_interface_add_prerequisite (vfs_job_source_type, G_TYPE_OBJECT); + } + + return vfs_job_source_type; +} + + +static void +g_vfs_job_source_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (! initialized) + { + initialized = TRUE; + + signals[NEW_JOB] = + g_signal_new ("new_job", + G_TYPE_VFS_JOB_SOURCE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVfsJobSourceIface, new_job), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_VFS_JOB); + + signals[CLOSED] = + g_signal_new ("closed", + G_TYPE_VFS_JOB_SOURCE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GVfsJobSourceIface, closed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + } +} + +/* +gboolean +g_vfs_job_source_is_native (GVfsJobSource *vfs_job_source) +{ + GVfsJobSourceIface *iface; + + iface = G_VFS_JOB_SOURCE_GET_IFACE (vfs_job_source); + + return (* iface->is_native) (vfs_job_source); +} +*/ + +void +g_vfs_job_source_new_job (GVfsJobSource *job_source, + GVfsJob *job) +{ + g_signal_emit (job_source, signals[NEW_JOB], 0, job); +} + +void +g_vfs_job_source_closed (GVfsJobSource *job_source) +{ + g_signal_emit (job_source, signals[CLOSED], 0); +} + +void +g_vfs_job_source_reset (GVfsJobSource *job_source) +{ + GVfsJobSourceIface *iface; + + iface = G_VFS_JOB_SOURCE_GET_IFACE (job_source); + + if (iface->reset) + (* iface->reset) (job_source); +} diff --git a/daemon/gvfsjobsource.h b/daemon/gvfsjobsource.h new file mode 100644 index 00000000..41696787 --- /dev/null +++ b/daemon/gvfsjobsource.h @@ -0,0 +1,43 @@ +#ifndef __G_VFS_JOB_SOURCE_H__ +#define __G_VFS_JOB_SOURCE_H__ + +#include <glib-object.h> +#include <gvfsjob.h> + +G_BEGIN_DECLS + +#define G_TYPE_VFS_JOB_SOURCE (g_vfs_job_source_get_type ()) +#define G_VFS_JOB_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_VFS_JOB_SOURCE, GVfsJobSource)) +#define G_IS_VFS_JOB_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_VFS_JOB_SOURCE)) +#define G_VFS_JOB_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_VFS_JOB_SOURCE, GVfsJobSourceIface)) + +/* GVfsJobSource defined in gvfsjob.h */ +typedef struct _GVfsJobSourceIface GVfsJobSourceIface; + +struct _GVfsJobSourceIface +{ + GTypeInterface g_iface; + + /* Virtual Table: */ + + void (*reset) (GVfsJobSource *source); + + /* Signals: */ + + void (*new_job) (GVfsJobSource *source, + GVfsJob *job); + void (*closed) (GVfsJobSource *source); + +}; + +GType g_vfs_job_source_get_type (void) G_GNUC_CONST; + +void g_vfs_job_source_new_job (GVfsJobSource *job_source, + GVfsJob *job); +void g_vfs_job_source_closed (GVfsJobSource *job_source); +void g_vfs_job_source_reset (GVfsJobSource *job_source); + + +G_END_DECLS + +#endif /* __G_VFS_JOB_SOURCE_H__ */ diff --git a/daemon/gvfsmountpoint.c b/daemon/gvfsmountpoint.c new file mode 100644 index 00000000..1ac35dc7 --- /dev/null +++ b/daemon/gvfsmountpoint.c @@ -0,0 +1,61 @@ +#include <config.h> +#include <gvfsmountpoint.h> +#include <gvfsdaemonutils.h> + +GVfsMountpoint * +g_vfs_mountpoint_copy (GVfsMountpoint *mountpoint) +{ + GVfsMountpoint *copy; + + copy = g_new (GVfsMountpoint, 1); + copy->method = g_strdup (mountpoint->method); + copy->user = g_strdup (mountpoint->user); + copy->host = g_strdup (mountpoint->host); + copy->port = mountpoint->port; + copy->path = g_strdup (mountpoint->path); + + return copy; +} + +void +g_vfs_mountpoint_free (GVfsMountpoint *mountpoint) +{ + g_free (mountpoint->method); + g_free (mountpoint->user); + g_free (mountpoint->host); + g_free (mountpoint->path); + g_free (mountpoint); +} + +GVfsMountpoint * +g_vfs_mountpoint_from_dbus (DBusMessageIter *iter) +{ + return NULL; +} + +void +g_vfs_mountpoint_to_dbus (GVfsMountpoint *mountpoint, + DBusMessageIter *iter) +{ + dbus_bool_t res; + dbus_int32_t port; + + res = TRUE; + res &= dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, + &mountpoint->method); + + /* TODO: Is this always utf8? */ + res &= dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, + &mountpoint->user); + + res &= dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, + &mountpoint->host); + + port = mountpoint->port; + res &= dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &port); + + res &= _g_dbus_message_iter_append_filename (iter, mountpoint->path); + + if (!res) + g_error ("out of memory"); +} diff --git a/daemon/gvfsmountpoint.h b/daemon/gvfsmountpoint.h new file mode 100644 index 00000000..12459fe9 --- /dev/null +++ b/daemon/gvfsmountpoint.h @@ -0,0 +1,22 @@ +#ifndef __G_VFS_MOUNTPOINT_H__ +#define __G_VFS_MOUNTPOINT_H__ + +#include <glib.h> +#include <dbus/dbus.h> + + +typedef struct { + char *method; + char *user; + char *host; + int port; + char *path; +} GVfsMountpoint; + +GVfsMountpoint *g_vfs_mountpoint_copy (GVfsMountpoint *mountpoint); +void g_vfs_mountpoint_free (GVfsMountpoint *mountpoint); +GVfsMountpoint *g_vfs_mountpoint_from_dbus (DBusMessageIter *iter); +void g_vfs_mountpoint_to_dbus (GVfsMountpoint *mountpoint, + DBusMessageIter *iter); + +#endif /* __G_VFS_MOUNTPOINT_H__ */ diff --git a/daemon/gvfsreadchannel.c b/daemon/gvfsreadchannel.c index 54a0d2c5..71ad17ff 100644 --- a/daemon/gvfsreadchannel.c +++ b/daemon/gvfsreadchannel.c @@ -21,20 +21,16 @@ #include <gvfsjobseekread.h> #include <gvfsjobcloseread.h> -G_DEFINE_TYPE (GVfsReadChannel, g_vfs_read_channel, G_TYPE_OBJECT); +static void g_vfs_read_channel_job_source_iface_init (GVfsJobSourceIface *iface); -enum { - PROP_0, -}; +G_DEFINE_TYPE_WITH_CODE (GVfsReadChannel, g_vfs_read_channel, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_VFS_JOB_SOURCE, + g_vfs_read_channel_job_source_iface_init)) enum { - NEW_JOB, - CLOSED, - LAST_SIGNAL + PROP_0, }; -static guint signals[LAST_SIGNAL] = { 0 }; - typedef struct { GVfsReadChannel *read_channel; @@ -101,6 +97,11 @@ g_vfs_read_channel_finalize (GObject *object) } static void +g_vfs_read_channel_job_source_iface_init (GVfsJobSourceIface *iface) +{ +} + +static void g_vfs_read_channel_class_init (GVfsReadChannelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); @@ -108,25 +109,6 @@ g_vfs_read_channel_class_init (GVfsReadChannelClass *klass) g_type_class_add_private (klass, sizeof (GVfsReadChannelPrivate)); gobject_class->finalize = g_vfs_read_channel_finalize; - - signals[NEW_JOB] = - g_signal_new ("new_job", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVfsReadChannelClass, new_job), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_VFS_JOB); - - signals[CLOSED] = - g_signal_new ("closed", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GVfsReadChannelClass, closed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - } static void @@ -150,7 +132,7 @@ g_vfs_read_channel_connection_closed (GVfsReadChannel *channel) { channel->priv->current_job = g_vfs_job_close_read_new (channel, channel->priv->backend_handle, channel->priv->backend); channel->priv->current_job_seq_nr = 0; - g_signal_emit (channel, signals[NEW_JOB], 0, channel->priv->current_job); + g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job); } /* Otherwise we'll close when current_job is finished */ } @@ -230,7 +212,7 @@ got_command (GVfsReadChannel *channel, { channel->priv->current_job = job; channel->priv->current_job_seq_nr = seq_nr; - g_signal_emit (channel, signals[NEW_JOB], 0, job); + g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job); } } @@ -385,7 +367,7 @@ send_reply_cb (GOutputStream *output_stream, if (G_IS_VFS_JOB_CLOSE_READ (job)) { - g_signal_emit (channel, signals[CLOSED], 0); + g_vfs_job_source_closed (G_VFS_JOB_SOURCE (channel)); channel->priv->backend_handle = NULL; } else if (channel->priv->connection_closed) @@ -393,7 +375,7 @@ send_reply_cb (GOutputStream *output_stream, channel->priv->current_job = g_vfs_job_close_read_new (channel, channel->priv->backend_handle, channel->priv->backend); channel->priv->current_job_seq_nr = 0; - g_signal_emit (channel, signals[NEW_JOB], 0, channel->priv->current_job); + g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job); } g_object_unref (job); diff --git a/daemon/gvfsreadchannel.h b/daemon/gvfsreadchannel.h index 3ff59e1f..4e2b6d82 100644 --- a/daemon/gvfsreadchannel.h +++ b/daemon/gvfsreadchannel.h @@ -44,7 +44,7 @@ GVfsReadChannel *g_vfs_read_channel_new (GVfsBackend *back int g_vfs_read_channel_steal_remote_fd (GVfsReadChannel *read_channel); GVfsBackend *g_vfs_read_channel_get_backend (GVfsReadChannel *read_channel); void g_vfs_read_channel_set_backend_handle (GVfsReadChannel *read_channel, - GVfsBackendHandle backend_handle); + GVfsBackendHandle backend_handle); gboolean g_vfs_read_channel_has_job (GVfsReadChannel *read_channel); GVfsJob * g_vfs_read_channel_get_job (GVfsReadChannel *read_channel); void g_vfs_read_channel_send_data (GVfsReadChannel *read_channel, diff --git a/daemon/main.c b/daemon/main.c index 696d54c1..cd5b1e7a 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -1,58 +1,50 @@ #include <config.h> #include <glib.h> +#include <glib/gi18n.h> #include <dbus/dbus.h> #include <dbus-gmain.h> #include "gvfsdaemon.h" #include "gvfsbackendtest.h" #include <gvfsdaemonprotocol.h> -static gboolean -init_dbus (void) -{ - DBusConnection *conn; - DBusError error; - - dbus_error_init (&error); - - conn = dbus_bus_get (DBUS_BUS_SESSION, &error); - if (!conn) - { - g_printerr ("Failed to connect to the D-BUS daemon: %s\n", - error.message); - - dbus_error_free (&error); - return FALSE; - } - - dbus_connection_setup_with_g_main (conn, NULL); - - return TRUE; -} - - int main (int argc, char *argv[]) { GMainLoop *loop; GVfsDaemon *daemon; - GVfsBackendTest *backend; + gboolean replace; + GError *error; + GOptionContext *context; + const GOptionEntry options[] = { + { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, N_("Replace old daemon."), NULL }, + { NULL } + }; + + g_set_application_name (_("GVFS Daemon")); + context = g_option_context_new (_("")); + + g_option_context_set_summary (context, "Main daemon for GVFS"); + + g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); + replace = FALSE; + error = NULL; + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("%s, use --help for usage\n", error->message); + g_error_free (error); + return 1; + } + g_thread_init (NULL); g_type_init (); - if (!init_dbus ()) + daemon = g_vfs_daemon_new (TRUE, replace); + if (daemon == NULL) return 1; - daemon = g_vfs_daemon_new (); - - backend = g_vfs_backend_test_new (); - if (!g_vfs_daemon_add_backend (daemon, G_VFS_BACKEND (backend))) - return 1; - g_object_unref (backend); - - loop = g_main_loop_new (NULL, FALSE); g_print ("Entering mainloop\n"); diff --git a/dbus.txt b/dbus.txt new file mode 100644 index 00000000..88468d7d --- /dev/null +++ b/dbus.txt @@ -0,0 +1,21 @@ +The "main" daemon owns the org.gtk.vfs.Daemon bus name +When the main daemon looses org.gtk.vfs.Daemon, it quits. + +each "daemon" has a unique session bus id + +Each daemon registers /org/gtk/vfs/Daemon which supports +operations like GetConnection and CancelOp on iface org.gtk.vfs.Daemon. + +The main daemon supports ListMountpoints, iface org.gtk.vfs.MountpointTracker +at /org/gtk/vfs/MountpointTracker. It does this by tracking signals for availible +mountpoints and deaths of vfs daemons. + +Each "mountpoint" in a daemon registers a org.gtk.vfs.Mountpoint iface +at a path like /org/gtk/vfs/mountpoint/N. It also signals availibility of this +mountpoint (with the bus id and the "uri prefix") at startup and when there is +a new owner of "org.gtk.vfs.Daemon". + +At startup the client calls ListMountpoints to get a list of all active +mountpoints. It then continues to track changes by looking at signals for +availibility and daemon deaths. + |