summaryrefslogtreecommitdiff
path: root/gnome-2-24/client/gvfsdaemondbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-2-24/client/gvfsdaemondbus.c')
-rw-r--r--gnome-2-24/client/gvfsdaemondbus.c1024
1 files changed, 0 insertions, 1024 deletions
diff --git a/gnome-2-24/client/gvfsdaemondbus.c b/gnome-2-24/client/gvfsdaemondbus.c
deleted file mode 100644
index aabb8dea..00000000
--- a/gnome-2-24/client/gvfsdaemondbus.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/* GIO - GLib Input, Output and Streaming Library
- *
- * Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Alexander Larsson <alexl@redhat.com>
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <poll.h>
-
-#include <glib/gi18n-lib.h>
-
-#include <gio/gio.h>
-#include "gvfsdaemondbus.h"
-#include <gvfsdaemonprotocol.h>
-#include <gdaemonvfs.h>
-#include "gdbusutils.h"
-#include "gsysutils.h"
-
-/* Extra vfs-specific data for DBusConnections */
-typedef struct {
- int extra_fd;
- int extra_fd_count;
- char *async_dbus_id;
-
- /* Only used for async connections */
- GHashTable *outstanding_fds;
- GSource *extra_fd_source;
-} VfsConnectionData;
-
-static gint32 vfs_data_slot = -1;
-static GOnce once_init_dbus = G_ONCE_INIT;
-
-static GStaticPrivate local_connections = G_STATIC_PRIVATE_INIT;
-
-/* dbus id -> async connection */
-static GHashTable *async_map = NULL;
-G_LOCK_DEFINE_STATIC(async_map);
-
-/* dbus object path -> dbus message filter */
-static GHashTable *obj_path_map = NULL;
-G_LOCK_DEFINE_STATIC(obj_path_map);
-
-static void setup_async_fd_receive (VfsConnectionData *connection_data);
-static void invalidate_local_connection (const char *dbus_id,
- GError **error);
-
-
-GQuark
-_g_vfs_error_quark (void)
-{
- return g_quark_from_static_string ("g-vfs-error-quark");
-}
-
-static gpointer
-vfs_dbus_init (gpointer arg)
-{
- if (!dbus_connection_allocate_data_slot (&vfs_data_slot))
- g_error ("Unable to allocate data slot");
-
- return NULL;
-}
-
-/**************************************************************************
- * message filters for vfs dbus connections *
- *************************************************************************/
-
-typedef struct {
- DBusHandleMessageFunction callback;
- GObject *data;
-} PathMapEntry;
-
-void
-_g_dbus_register_vfs_filter (const char *obj_path,
- DBusHandleMessageFunction callback,
- GObject *data)
-{
- PathMapEntry * entry;
-
- G_LOCK (obj_path_map);
-
- if (obj_path_map == NULL)
- obj_path_map = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
-
- entry = g_new (PathMapEntry,1 );
- entry->callback = callback;
- entry->data = data;
-
- g_hash_table_insert (obj_path_map, g_strdup (obj_path), entry);
-
- G_UNLOCK (obj_path_map);
-}
-
-void
-_g_dbus_unregister_vfs_filter (const char *obj_path)
-{
- G_LOCK (obj_path_map);
-
- if (obj_path_map)
- g_hash_table_remove (obj_path_map, obj_path);
-
- G_UNLOCK (obj_path_map);
-}
-
-static DBusHandlerResult
-vfs_connection_filter (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- PathMapEntry *entry;
- DBusHandlerResult res;
- DBusHandleMessageFunction callback;
- GObject *data;
- VfsConnectionData *connection_data;
- const char *path;
-
- callback = NULL;
- data = NULL;
-
- if (dbus_message_is_signal (message,
- DBUS_INTERFACE_LOCAL,
- "Disconnected"))
- {
- connection_data = dbus_connection_get_data (connection, vfs_data_slot);
- if (connection_data->async_dbus_id)
- {
- _g_daemon_vfs_invalidate_dbus_id (connection_data->async_dbus_id);
- G_LOCK (async_map);
- g_hash_table_remove (async_map, connection_data->async_dbus_id);
- G_UNLOCK (async_map);
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- path = dbus_message_get_path (message);
- G_LOCK (obj_path_map);
- if (obj_path_map && path)
- {
- entry = g_hash_table_lookup (obj_path_map,
- path);
-
- if (entry)
- {
- callback = entry->callback;
- data = g_object_ref (entry->data);
- }
- }
- G_UNLOCK (obj_path_map);
-
- res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (callback)
- {
- res = callback (connection, message, data);
- g_object_unref (data);
- }
-
- return res;
-}
-
-static void
-connection_data_free (gpointer p)
-{
- VfsConnectionData *data = p;
-
- if (data->extra_fd != -1)
- close (data->extra_fd);
-
- if (data->extra_fd_source)
- {
- g_source_destroy (data->extra_fd_source);
- g_source_unref (data->extra_fd_source);
- }
-
- if (data->outstanding_fds)
- g_hash_table_destroy (data->outstanding_fds);
-
- g_free (data->async_dbus_id);
-
- g_free (data);
-}
-
-static void
-vfs_connection_setup (DBusConnection *connection,
- int extra_fd,
- gboolean async)
-{
- VfsConnectionData *connection_data;
-
- connection_data = g_new0 (VfsConnectionData, 1);
- connection_data->extra_fd = extra_fd;
- connection_data->extra_fd_count = 0;
-
- if (async)
- setup_async_fd_receive (connection_data);
-
- if (!dbus_connection_set_data (connection, vfs_data_slot, connection_data, connection_data_free))
- _g_dbus_oom ();
-
- if (!dbus_connection_add_filter (connection, vfs_connection_filter, NULL, NULL))
- _g_dbus_oom ();
-}
-
-/**************************************************************************
- * Functions to get fds from vfs dbus connections *
- *************************************************************************/
-
-typedef struct {
- int fd;
- GetFdAsyncCallback callback;
- gpointer callback_data;
-} OutstandingFD;
-
-static void
-outstanding_fd_free (OutstandingFD *outstanding)
-{
- if (outstanding->fd != -1)
- close (outstanding->fd);
-
- g_free (outstanding);
-}
-
-static void
-async_connection_accept_new_fd (VfsConnectionData *data,
- GIOCondition condition,
- int fd)
-{
- int new_fd;
- int fd_id;
- OutstandingFD *outstanding_fd;
-
- if (condition & G_IO_HUP)
- {
- close (data->extra_fd);
- data->extra_fd = -1;
- g_source_destroy (data->extra_fd_source);
- g_source_unref (data->extra_fd_source);
- data->extra_fd_source = NULL;
- return;
- }
-
- fd_id = data->extra_fd_count;
- new_fd = _g_socket_receive_fd (data->extra_fd);
- if (new_fd != -1)
- {
- data->extra_fd_count++;
-
- outstanding_fd = g_hash_table_lookup (data->outstanding_fds, GINT_TO_POINTER (fd_id));
-
- if (outstanding_fd)
- {
- outstanding_fd->callback (new_fd, outstanding_fd->callback_data);
- g_hash_table_remove (data->outstanding_fds, GINT_TO_POINTER (fd_id));
- }
- else
- {
- outstanding_fd = g_new0 (OutstandingFD, 1);
- outstanding_fd->fd = new_fd;
- outstanding_fd->callback = NULL;
- outstanding_fd->callback_data = NULL;
- g_hash_table_insert (data->outstanding_fds,
- GINT_TO_POINTER (fd_id),
- outstanding_fd);
- }
- }
-}
-
-static void
-setup_async_fd_receive (VfsConnectionData *connection_data)
-{
- connection_data->outstanding_fds =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- (GDestroyNotify)outstanding_fd_free);
-
-
- connection_data->extra_fd_source =
- __g_fd_source_new (connection_data->extra_fd, POLLIN|POLLERR, NULL);
- g_source_set_callback (connection_data->extra_fd_source,
- (GSourceFunc)async_connection_accept_new_fd,
- connection_data, NULL);
- g_source_attach (connection_data->extra_fd_source, NULL);
-}
-
-int
-_g_dbus_connection_get_fd_sync (DBusConnection *connection,
- int fd_id)
-{
- VfsConnectionData *data;
- int fd;
-
- data = dbus_connection_get_data (connection, vfs_data_slot);
- g_assert (data != NULL);
-
- /* I don't think we can get reorders here, can we?
- * Its a sync per-thread connection after all
- */
- g_assert (fd_id == data->extra_fd_count);
-
- fd = _g_socket_receive_fd (data->extra_fd);
- if (fd != -1)
- data->extra_fd_count++;
-
- return fd;
-}
-
-void
-_g_dbus_connection_get_fd_async (DBusConnection *connection,
- int fd_id,
- GetFdAsyncCallback callback,
- gpointer callback_data)
-{
- VfsConnectionData *data;
- OutstandingFD *outstanding_fd;
- int fd;
-
- data = dbus_connection_get_data (connection, vfs_data_slot);
- g_assert (data != NULL);
-
- outstanding_fd = g_hash_table_lookup (data->outstanding_fds, GINT_TO_POINTER (fd_id));
-
- if (outstanding_fd)
- {
- fd = outstanding_fd->fd;
- outstanding_fd->fd = -1;
- g_hash_table_remove (data->outstanding_fds, GINT_TO_POINTER (fd_id));
- callback (fd, callback_data);
- }
- else
- {
- outstanding_fd = g_new0 (OutstandingFD, 1);
- outstanding_fd->fd = -1;
- outstanding_fd->callback = callback;
- outstanding_fd->callback_data = callback_data;
- g_hash_table_insert (data->outstanding_fds,
- GINT_TO_POINTER (fd_id),
- outstanding_fd);
- }
-}
-
-/*******************************************************************
- * Caching of async connections *
- *******************************************************************/
-
-
-static DBusConnection *
-get_connection_for_async (const char *dbus_id)
-{
- DBusConnection *connection;
-
- connection = NULL;
- G_LOCK (async_map);
- if (async_map != NULL)
- connection = g_hash_table_lookup (async_map, dbus_id);
- if (connection)
- dbus_connection_ref (connection);
- G_UNLOCK (async_map);
-
- return connection;
-}
-
-static void
-close_and_unref_connection (void *data)
-{
- DBusConnection *connection = data;
-
- dbus_connection_close (connection);
- dbus_connection_unref (connection);
-}
-
-static void
-set_connection_for_async (DBusConnection *connection, const char *dbus_id)
-{
- VfsConnectionData *data;
-
- G_LOCK (async_map);
- data = dbus_connection_get_data (connection, vfs_data_slot);
- data->async_dbus_id = g_strdup (dbus_id);
-
- if (async_map == NULL)
- async_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, close_and_unref_connection);
-
- g_hash_table_insert (async_map, g_strdup (dbus_id), connection);
- dbus_connection_ref (connection);
- G_UNLOCK (async_map);
-}
-
-/**************************************************************************
- * Asynchronous daemon calls *
- *************************************************************************/
-
-typedef struct {
- const char *dbus_id;
-
- DBusMessage *message;
- DBusConnection *connection;
- GCancellable *cancellable;
-
- GVfsAsyncDBusCallback callback;
- gpointer callback_data;
-
- GError *io_error;
- gulong cancelled_tag;
-} AsyncDBusCall;
-
-static void
-async_call_finish (AsyncDBusCall *async_call,
- DBusMessage *reply)
-{
- if (async_call->callback)
- async_call->callback (reply, async_call->connection,
- async_call->io_error,
- async_call->callback_data);
-
- if (async_call->connection)
- dbus_connection_unref (async_call->connection);
- dbus_message_unref (async_call->message);
- if (async_call->cancellable)
- g_object_unref (async_call->cancellable);
- if (async_call->io_error)
- g_error_free (async_call->io_error);
- g_free (async_call);
-}
-
-static void
-async_dbus_response (DBusMessage *reply,
- GError *error,
- gpointer data)
-{
- AsyncDBusCall *async_call = data;
-
- if (async_call->cancelled_tag)
- g_signal_handler_disconnect (async_call->cancellable,
- async_call->cancelled_tag);
-
- if (reply == NULL)
- async_call->io_error = g_error_copy (error);
-
- async_call_finish (async_call, reply);
-}
-
-typedef struct {
- DBusConnection *connection;
- dbus_uint32_t serial;
-} AsyncCallCancelData;
-
-static void
-async_call_cancel_data_free (gpointer _data)
-{
- AsyncCallCancelData *data = _data;
-
- dbus_connection_unref (data->connection);
- g_free (data);
-}
-
-/* Might be called on another thread */
-static void
-async_call_cancelled_cb (GCancellable *cancellable,
- gpointer _data)
-{
- AsyncCallCancelData *data = _data;
- DBusMessage *cancel_message;
-
- /* Send cancellation message, this just queues it, sending
- * will happen in mainloop */
- cancel_message = dbus_message_new_method_call (NULL,
- G_VFS_DBUS_DAEMON_PATH,
- G_VFS_DBUS_DAEMON_INTERFACE,
- G_VFS_DBUS_OP_CANCEL);
- if (cancel_message != NULL)
- {
- if (dbus_message_append_args (cancel_message,
- DBUS_TYPE_UINT32, &data->serial,
- DBUS_TYPE_INVALID))
- dbus_connection_send (data->connection,
- cancel_message, NULL);
- dbus_message_unref (cancel_message);
- }
-}
-
-static void
-async_call_send (AsyncDBusCall *async_call)
-{
- AsyncCallCancelData *cancel_data;
-
- if (async_call->cancellable)
- {
- cancel_data = g_new0 (AsyncCallCancelData, 1);
- cancel_data->connection = dbus_connection_ref (async_call->connection);
- cancel_data->serial = dbus_message_get_serial (async_call->message);
- async_call->cancelled_tag =
- g_signal_connect_data (async_call->cancellable, "cancelled",
- (GCallback)async_call_cancelled_cb,
- cancel_data,
- (GClosureNotify)async_call_cancel_data_free,
- 0);
- }
-
- _g_dbus_connection_call_async (async_call->connection,
- async_call->message,
- G_VFS_DBUS_TIMEOUT_MSECS,
- async_dbus_response,
- async_call);
-}
-
-static void
-async_get_connection_response (DBusMessage *reply,
- GError *error,
- void *data)
-{
- AsyncDBusCall *async_call = data;
- DBusError derror;
- char *address1, *address2;
- int extra_fd;
- DBusConnection *connection, *existing_connection;
-
- if (reply == NULL)
- {
- async_call->io_error = g_error_copy (error);
- async_call_finish (async_call, NULL);
- return;
- }
-
- dbus_error_init (&derror);
- if (!dbus_message_get_args (reply, &derror,
- DBUS_TYPE_STRING, &address1,
- DBUS_TYPE_STRING, &address2,
- DBUS_TYPE_INVALID))
- {
- _g_error_from_dbus (&derror, &async_call->io_error);
- dbus_error_free (&derror);
- async_call_finish (async_call, NULL);
- return;
- }
-
- /* I don't know of any way to do an async connect */
- error = NULL;
- extra_fd = _g_socket_connect (address2, &error);
- if (extra_fd == -1)
- {
- g_set_error (&async_call->io_error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Error connecting to daemon: %s"), error->message);
- g_error_free (error);
- async_call_finish (async_call, NULL);
- return;
- }
-
- /* Unfortunately dbus doesn't have an async open */
- dbus_error_init (&derror);
- connection = dbus_connection_open_private (address1, &derror);
- if (!connection)
- {
- close (extra_fd);
- dbus_message_unref (reply);
-
- g_set_error (&async_call->io_error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error while getting peer-to-peer dbus connection: %s",
- derror.message);
- dbus_error_free (&derror);
- async_call_finish (async_call, NULL);
- return;
- }
-
- vfs_connection_setup (connection, extra_fd, TRUE);
-
- /* Maybe we already had a connection? This happens if we requested
- * the same owner several times in parallel.
- * If so, just drop this connection and use that.
- */
-
- existing_connection = get_connection_for_async (async_call->dbus_id);
- if (existing_connection != NULL)
- {
- async_call->connection = existing_connection;
- dbus_connection_close (connection);
- dbus_connection_unref (connection);
- }
- else
- {
- _g_dbus_connection_integrate_with_main (connection);
- set_connection_for_async (connection, async_call->dbus_id);
- async_call->connection = connection;
- }
-
- /* Maybe we were canceled while setting up connection, then
- * avoid doing the operation */
- if (g_cancellable_set_error_if_cancelled (async_call->cancellable, &async_call->io_error))
- {
- async_call_finish (async_call, NULL);
- return;
- }
-
- async_call_send (async_call);
-}
-
-static void
-open_connection_async (AsyncDBusCall *async_call)
-{
- DBusMessage *get_connection_message;
-
- get_connection_message = dbus_message_new_method_call (async_call->dbus_id,
- G_VFS_DBUS_DAEMON_PATH,
- G_VFS_DBUS_DAEMON_INTERFACE,
- G_VFS_DBUS_OP_GET_CONNECTION);
-
- if (get_connection_message == NULL)
- _g_dbus_oom ();
-
-
- _g_dbus_connection_call_async (_g_daemon_vfs_get_async_bus (),
- get_connection_message,
- G_VFS_DBUS_TIMEOUT_MSECS,
- async_get_connection_response,
- async_call);
-
- dbus_message_unref (get_connection_message);
-}
-
-void
-_g_vfs_daemon_call_async (DBusMessage *message,
- GVfsAsyncDBusCallback callback,
- gpointer callback_data,
- GCancellable *cancellable)
-{
- AsyncDBusCall *async_call;
-
- g_once (&once_init_dbus, vfs_dbus_init, NULL);
-
- async_call = g_new0 (AsyncDBusCall, 1);
- async_call->dbus_id = dbus_message_get_destination (message);
- async_call->message = dbus_message_ref (message);
- if (cancellable)
- async_call->cancellable = g_object_ref (cancellable);
- async_call->callback = callback;
- async_call->callback_data = callback_data;
-
- async_call->connection = get_connection_for_async (async_call->dbus_id);
- if (async_call->connection == NULL)
- open_connection_async (async_call);
- else
- async_call_send (async_call);
-}
-
-/**************************************************************************
- * Synchronous daemon calls *
- *************************************************************************/
-
-DBusMessage *
-_g_vfs_daemon_call_sync (DBusMessage *message,
- DBusConnection **connection_out,
- const char *callback_obj_path,
- DBusObjectPathMessageFunction callback,
- gpointer callback_user_data,
- GCancellable *cancellable,
- GError **error)
-{
- DBusConnection *connection;
- DBusError derror;
- DBusMessage *reply;
- DBusPendingCall *pending;
- int dbus_fd;
- int cancel_fd;
- gboolean sent_cancel;
- DBusMessage *cancel_message;
- dbus_uint32_t serial;
- gboolean handle_callbacks;
- const char *dbus_id = dbus_message_get_destination (message);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
-
- connection = _g_dbus_connection_get_sync (dbus_id, error);
- if (connection == NULL)
- return NULL;
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
-
- handle_callbacks = FALSE;
- if (callback_obj_path != NULL && callback != NULL)
- {
- struct DBusObjectPathVTable vtable = { NULL, callback };
- handle_callbacks = dbus_connection_register_object_path (connection,
- callback_obj_path,
- &vtable,
- callback_user_data);
- }
-
- reply = NULL;
- cancel_fd = g_cancellable_get_fd (cancellable);
- if (cancel_fd != -1 || handle_callbacks)
- {
- if (!dbus_connection_send_with_reply (connection, message,
- &pending,
- G_VFS_DBUS_TIMEOUT_MSECS))
- _g_dbus_oom ();
-
- if (pending == NULL ||
- !dbus_connection_get_is_connected (connection))
- {
- if (pending)
- dbus_pending_call_unref (pending);
- invalidate_local_connection (dbus_id, error);
- goto out;
- }
-
- /* Make sure the message is sent */
- dbus_connection_flush (connection);
-
- if (!dbus_connection_get_unix_fd (connection, &dbus_fd))
- {
- dbus_pending_call_unref (pending);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error while getting peer-to-peer dbus connection: %s",
- "No fd");
- goto out;
- }
-
- sent_cancel = (cancel_fd == -1);
- while (!dbus_pending_call_get_completed (pending))
- {
- struct pollfd poll_fds[2];
- int poll_ret;
-
- do
- {
- poll_fds[0].events = POLLIN;
- poll_fds[0].fd = dbus_fd;
- poll_fds[1].events = POLLIN;
- poll_fds[1].fd = cancel_fd;
- poll_ret = poll (poll_fds, sent_cancel?1:2, -1);
- }
- while (poll_ret == -1 && errno == EINTR);
-
- if (poll_ret == -1)
- {
- dbus_pending_call_unref (pending);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error while getting peer-to-peer dbus connection: %s",
- "poll error");
- goto out;
- }
-
- if (!sent_cancel && g_cancellable_is_cancelled (cancellable))
- {
- sent_cancel = TRUE;
- serial = dbus_message_get_serial (message);
- cancel_message =
- dbus_message_new_method_call (NULL,
- G_VFS_DBUS_DAEMON_PATH,
- G_VFS_DBUS_DAEMON_INTERFACE,
- G_VFS_DBUS_OP_CANCEL);
- if (cancel_message != NULL)
- {
- if (dbus_message_append_args (cancel_message,
- DBUS_TYPE_UINT32, &serial,
- DBUS_TYPE_INVALID))
- {
- dbus_connection_send (connection, cancel_message, NULL);
- dbus_connection_flush (connection);
- }
-
- dbus_message_unref (cancel_message);
- }
- }
-
- if (poll_fds[0].revents != 0)
- {
- dbus_connection_read_write (connection,
- G_VFS_DBUS_TIMEOUT_MSECS);
-
- while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
- ;
- }
- }
-
- reply = dbus_pending_call_steal_reply (pending);
- dbus_pending_call_unref (pending);
- }
- else
- {
- dbus_error_init (&derror);
- reply = dbus_connection_send_with_reply_and_block (connection, message,
- G_VFS_DBUS_TIMEOUT_MSECS,
- &derror);
- if (!reply)
- {
- if (dbus_error_has_name (&derror, DBUS_ERROR_NO_REPLY) &&
- !dbus_connection_get_is_connected (connection))
- {
- /* The mount for this connection died, we invalidate
- * the caches, and then caller needs to retry.
- */
-
- invalidate_local_connection (dbus_id, error);
- }
- else
- _g_error_from_dbus (&derror, error);
- dbus_error_free (&derror);
- goto out;
- }
- }
-
- if (connection_out)
- *connection_out = connection;
-
- out:
-
- if (handle_callbacks)
- dbus_connection_unregister_object_path (connection, callback_obj_path);
-
- if (reply != NULL && _g_error_from_message (reply, error))
- {
- dbus_message_unref (reply);
- return NULL;
- }
-
- return reply;
-}
-
-/*************************************************************************
- * get per-thread synchronous dbus connections *
- *************************************************************************/
-
-typedef struct {
- GHashTable *connections;
- DBusConnection *session_bus;
-} ThreadLocalConnections;
-
-static void
-free_mount_connection (DBusConnection *conn)
-{
- dbus_connection_close (conn);
- dbus_connection_unref (conn);
-}
-
-static void
-free_local_connections (ThreadLocalConnections *local)
-{
- g_hash_table_destroy (local->connections);
- if (local->session_bus)
- free_mount_connection (local->session_bus);
- g_free (local);
-}
-
-static void
-invalidate_local_connection (const char *dbus_id,
- GError **error)
-{
- ThreadLocalConnections *local;
-
- _g_daemon_vfs_invalidate_dbus_id (dbus_id);
-
- local = g_static_private_get (&local_connections);
- if (local)
- g_hash_table_remove (local->connections, dbus_id);
-
- g_set_error_literal (error,
- G_VFS_ERROR,
- G_VFS_ERROR_RETRY,
- "Cache invalid, retry (internally handled)");
-}
-
-DBusConnection *
-_g_dbus_connection_get_sync (const char *dbus_id,
- GError **error)
-{
- DBusConnection *bus;
- ThreadLocalConnections *local;
- GError *local_error;
- DBusConnection *connection;
- DBusMessage *message, *reply;
- DBusError derror;
- char *address1, *address2;
- int extra_fd;
-
- g_once (&once_init_dbus, vfs_dbus_init, NULL);
-
- local = g_static_private_get (&local_connections);
- if (local == NULL)
- {
- local = g_new0 (ThreadLocalConnections, 1);
- local->connections = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify)free_mount_connection);
- g_static_private_set (&local_connections, local, (GDestroyNotify)free_local_connections);
- }
-
- if (dbus_id == NULL)
- {
- /* Session bus */
-
- if (local->session_bus)
- {
- if (dbus_connection_get_is_connected (local->session_bus))
- return local->session_bus;
-
- /* Session bus was disconnected, re-connect */
- local->session_bus = NULL;
- dbus_connection_unref (local->session_bus);
- }
- }
- else
- {
- /* Mount daemon connection */
-
- connection = g_hash_table_lookup (local->connections, dbus_id);
- if (connection != NULL)
- {
- if (!dbus_connection_get_is_connected (connection))
- {
- /* The mount for this connection died, we invalidate
- * the caches, and then caller needs to retry.
- */
-
- invalidate_local_connection (dbus_id, error);
- return NULL;
- }
-
- return connection;
- }
- }
-
- dbus_error_init (&derror);
-
- if (local->session_bus == NULL)
- {
- bus = dbus_bus_get_private (DBUS_BUS_SESSION, &derror);
- if (bus == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Couldn't get main dbus connection: %s",
- derror.message);
- dbus_error_free (&derror);
- return NULL;
- }
-
- local->session_bus = bus;
-
- if (dbus_id == NULL)
- return bus; /* We actually wanted the session bus, so done */
- }
-
- message = dbus_message_new_method_call (dbus_id,
- G_VFS_DBUS_DAEMON_PATH,
- G_VFS_DBUS_DAEMON_INTERFACE,
- G_VFS_DBUS_OP_GET_CONNECTION);
- reply = dbus_connection_send_with_reply_and_block (local->session_bus, message, -1,
- &derror);
- dbus_message_unref (message);
-
- if (!reply)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error while getting peer-to-peer dbus connection: %s",
- derror.message);
- dbus_error_free (&derror);
- return NULL;
- }
-
- if (_g_error_from_message (reply, error))
- return NULL;
-
- dbus_message_get_args (reply, NULL,
- DBUS_TYPE_STRING, &address1,
- DBUS_TYPE_STRING, &address2,
- DBUS_TYPE_INVALID);
-
- local_error = NULL;
- extra_fd = _g_socket_connect (address2, &local_error);
- if (extra_fd == -1)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Error connecting to daemon: %s"), local_error->message);
- g_error_free (local_error);
- dbus_message_unref (reply);
- return NULL;
- }
-
- dbus_error_init (&derror);
- connection = dbus_connection_open_private (address1, &derror);
- if (!connection)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error while getting peer-to-peer dbus connection: %s",
- derror.message);
- close (extra_fd);
- dbus_message_unref (reply);
- dbus_error_free (&derror);
- return NULL;
- }
- dbus_message_unref (reply);
-
- vfs_connection_setup (connection, extra_fd, FALSE);
-
- g_hash_table_insert (local->connections, g_strdup (dbus_id), connection);
-
- return connection;
-}