summaryrefslogtreecommitdiff
path: root/trunk/client/gdaemonvfs.c
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@src.gnome.org>2009-03-16 11:43:23 +0000
committerAlexander Larsson <alexl@src.gnome.org>2009-03-16 11:43:23 +0000
commit4ad537c5c3e17e1efe289020d7dc6cd0efae42c5 (patch)
tree891f2ec720f5ae321762965a00d352ad0a1592a2 /trunk/client/gdaemonvfs.c
parent4c59b80ab2b0e942bd45ff12f238038293d21821 (diff)
downloadgvfs-82d3197d52d9a1f8a1a1b928e2550444138d088b.tar.gz
Tagged for release 1.2.0GVFS_1_2_0
svn path=/tags/GVFS_1_2_0/; revision=2331
Diffstat (limited to 'trunk/client/gdaemonvfs.c')
-rw-r--r--trunk/client/gdaemonvfs.c1152
1 files changed, 1152 insertions, 0 deletions
diff --git a/trunk/client/gdaemonvfs.c b/trunk/client/gdaemonvfs.c
new file mode 100644
index 00000000..c9f2cc97
--- /dev/null
+++ b/trunk/client/gdaemonvfs.c
@@ -0,0 +1,1152 @@
+/* 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 <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <dbus/dbus.h>
+#include "gdaemonvfs.h"
+#include "gvfsuriutils.h"
+#include "gdaemonfile.h"
+#include <gio/gio.h>
+#include <gvfsdaemonprotocol.h>
+#include <gmodule.h>
+#include "gvfsdaemondbus.h"
+#include "gdbusutils.h"
+#include "gmountspec.h"
+#include "gvfsurimapper.h"
+#include "gdaemonvolumemonitor.h"
+#include "gvfsicon.h"
+#include "gvfsiconloadable.h"
+#include <glib/gi18n-lib.h>
+
+typedef struct {
+ char *type;
+ char *scheme;
+ char **scheme_aliases;
+ int default_port;
+ gboolean host_is_inet;
+} MountableInfo;
+
+struct _GDaemonVfs
+{
+ GVfs parent;
+
+ DBusConnection *async_bus;
+
+ GVfs *wrapped_vfs;
+ GList *mount_cache;
+
+ GFile *fuse_root;
+
+ GHashTable *from_uri_hash;
+ GHashTable *to_uri_hash;
+
+ MountableInfo **mountable_info;
+ char **supported_uri_schemes;
+};
+
+struct _GDaemonVfsClass
+{
+ GVfsClass parent_class;
+};
+
+G_DEFINE_DYNAMIC_TYPE (GDaemonVfs, g_daemon_vfs, G_TYPE_VFS)
+
+static GDaemonVfs *the_vfs = NULL;
+
+G_LOCK_DEFINE_STATIC(mount_cache);
+
+
+static void fill_mountable_info (GDaemonVfs *vfs);
+
+static void
+g_daemon_vfs_finalize (GObject *object)
+{
+ GDaemonVfs *vfs;
+
+ vfs = G_DAEMON_VFS (object);
+
+ if (vfs->from_uri_hash)
+ g_hash_table_destroy (vfs->from_uri_hash);
+
+ if (vfs->to_uri_hash)
+ g_hash_table_destroy (vfs->to_uri_hash);
+
+ g_strfreev (vfs->supported_uri_schemes);
+
+ if (vfs->async_bus)
+ {
+ dbus_connection_close (vfs->async_bus);
+ dbus_connection_unref (vfs->async_bus);
+ }
+
+ if (vfs->wrapped_vfs)
+ g_object_unref (vfs->wrapped_vfs);
+
+ /* must chain up */
+ G_OBJECT_CLASS (g_daemon_vfs_parent_class)->finalize (object);
+}
+
+static MountableInfo *
+get_mountable_info_for_scheme (GDaemonVfs *vfs,
+ const char *scheme)
+{
+ MountableInfo *info;
+ int i, j;
+
+ if (vfs->mountable_info == NULL)
+ return NULL;
+
+ for (i = 0; vfs->mountable_info[i] != NULL; i++)
+ {
+ info = vfs->mountable_info[i];
+
+ if (info->scheme != NULL && strcmp (info->scheme, scheme) == 0)
+ return info;
+
+ if (info->scheme_aliases != NULL)
+ {
+ for (j = 0; info->scheme_aliases[j] != NULL; j++)
+ {
+ if (strcmp (info->scheme_aliases[j], scheme) == 0)
+ return info;
+ }
+ }
+
+ }
+
+ return NULL;
+}
+
+static MountableInfo *
+get_mountable_info_for_type (GDaemonVfs *vfs,
+ const char *type)
+{
+ MountableInfo *info;
+ int i;
+
+ if (vfs->mountable_info == NULL)
+ return NULL;
+
+ for (i = 0; vfs->mountable_info[i] != NULL; i++)
+ {
+ info = vfs->mountable_info[i];
+
+ if (strcmp (info->type, type) == 0)
+ return info;
+ }
+
+ return NULL;
+}
+
+static void
+str_tolower_inplace (char *str)
+{
+ char *p = str;
+
+ while (*p != 0)
+ {
+ *p = g_ascii_tolower (*p);
+ p++;
+ }
+
+}
+
+static gboolean
+get_mountspec_from_uri (GDaemonVfs *vfs,
+ const char *uri,
+ GMountSpec **spec_out,
+ char **path_out)
+{
+ GMountSpec *spec;
+ char *path;
+ GVfsUriMapper *mapper;
+ char *scheme;
+ GVfsUriMountInfo *info;
+
+ scheme = g_uri_parse_scheme (uri);
+ if (scheme == NULL)
+ return FALSE;
+
+ /* convert the scheme to lower case since g_uri_parse_scheme
+ * doesn't do that and we compare with g_str_equal */
+ str_tolower_inplace (scheme);
+
+ spec = NULL;
+ path = NULL;
+
+ mapper = g_hash_table_lookup (vfs->from_uri_hash, scheme);
+
+ if (mapper)
+ {
+ info = g_vfs_uri_mapper_from_uri (mapper, uri);
+ if (info != NULL)
+ {
+ spec = g_mount_spec_new_from_data (info->keys, NULL);
+ path = info->path;
+ /* We took over ownership of info parts, custom free: */
+ g_free (info);
+ }
+ }
+
+ if (spec == NULL)
+ {
+ GDecodedUri *decoded;
+ MountableInfo *mountable;
+ char *type;
+ int l;
+
+ decoded = g_vfs_decode_uri (uri);
+ if (decoded)
+ {
+ mountable = get_mountable_info_for_scheme (vfs, decoded->scheme);
+
+ if (mountable)
+ type = mountable->type;
+ else
+ type = decoded->scheme;
+
+ spec = g_mount_spec_new (type);
+
+ if (decoded->host && *decoded->host)
+ {
+ if (mountable && mountable->host_is_inet)
+ {
+ /* Convert hostname to lower case */
+ str_tolower_inplace (decoded->host);
+
+ /* Remove brackets aroung ipv6 addresses */
+ l = strlen (decoded->host);
+ if (decoded->host[0] == '[' &&
+ decoded->host[l - 1] == ']')
+ g_mount_spec_set_with_len (spec, "host", decoded->host+1, l - 2);
+ else
+ g_mount_spec_set (spec, "host", decoded->host);
+ }
+ else
+ g_mount_spec_set (spec, "host", decoded->host);
+ }
+
+ if (decoded->userinfo && *decoded->userinfo)
+ g_mount_spec_set (spec, "user", decoded->userinfo);
+
+ if (decoded->port != -1 &&
+ (mountable == NULL ||
+ mountable->default_port == 0 ||
+ mountable->default_port != decoded->port))
+ {
+ char *port = g_strdup_printf ("%d", decoded->port);
+ g_mount_spec_set (spec, "port", port);
+ g_free (port);
+ }
+
+ if (decoded->query && *decoded->query)
+ g_mount_spec_set (spec, "query", decoded->query);
+ if (decoded->fragment && *decoded->fragment)
+ g_mount_spec_set (spec, "fragment", decoded->fragment);
+
+ path = g_strdup (decoded->path);
+
+ g_vfs_decoded_uri_free (decoded);
+ }
+ }
+
+ g_free (scheme);
+
+ if (spec == NULL)
+ return FALSE;
+
+ *spec_out = spec;
+ *path_out = path;
+
+ return TRUE;
+}
+
+static void
+g_daemon_vfs_init (GDaemonVfs *vfs)
+{
+ GType *mappers;
+ guint n_mappers;
+ const char * const *schemes, * const *mount_types;
+ GVfsUriMapper *mapper;
+ GList *modules;
+ char *file;
+ int i;
+
+ bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ vfs->async_bus = dbus_bus_get_private (DBUS_BUS_SESSION, NULL);
+
+ if (vfs->async_bus == NULL)
+ return; /* Not supported, return here and return false in vfs_is_active() */
+
+ g_assert (the_vfs == NULL);
+ the_vfs = vfs;
+
+ if (g_thread_supported ())
+ dbus_threads_init_default ();
+
+ /* We disable SIGPIPE globally. This is sort of bad
+ for s library to do since its a global resource.
+ However, without this there is no way to be able
+ to handle mount daemons dying without client apps
+ crashing, which is much worse.
+
+ I blame Unix, there really should be a portable
+ way to do this on all unixes, but there isn't,
+ even for somewhat modern ones like solaris.
+ */
+ signal (SIGPIPE, SIG_IGN);
+
+ fill_mountable_info (vfs);
+
+ vfs->wrapped_vfs = g_vfs_get_local ();
+
+ file = g_build_filename (g_get_home_dir(), ".gvfs", NULL);
+ vfs->fuse_root = g_vfs_get_file_for_path (vfs->wrapped_vfs, file);
+ g_free (file);
+
+ dbus_connection_set_exit_on_disconnect (vfs->async_bus, FALSE);
+
+ _g_dbus_connection_integrate_with_main (vfs->async_bus);
+
+ modules = g_io_modules_load_all_in_directory (GVFS_MODULE_DIR);
+
+ vfs->from_uri_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ vfs->to_uri_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ mappers = g_type_children (G_VFS_TYPE_URI_MAPPER, &n_mappers);
+
+ for (i = 0; i < n_mappers; i++)
+ {
+ int j;
+ mapper = g_object_new (mappers[i], NULL);
+
+ schemes = g_vfs_uri_mapper_get_handled_schemes (mapper);
+
+ for (j = 0; schemes != NULL && schemes[j] != NULL; j++)
+ g_hash_table_insert (vfs->from_uri_hash, (char *)schemes[j], mapper);
+
+ mount_types = g_vfs_uri_mapper_get_handled_mount_types (mapper);
+ for (j = 0; mount_types != NULL && mount_types[j] != NULL; j++)
+ g_hash_table_insert (vfs->to_uri_hash, (char *)mount_types[j], mapper);
+ }
+
+ /* The above should have ref:ed the modules anyway */
+ g_list_foreach (modules, (GFunc)g_type_module_unuse, NULL);
+ g_list_free (modules);
+ g_free (mappers);
+}
+
+GDaemonVfs *
+g_daemon_vfs_new (void)
+{
+ return g_object_new (G_TYPE_DAEMON_VFS, NULL);
+}
+
+/* This unrefs file if its changed */
+static GFile *
+convert_fuse_path (GVfs *vfs,
+ GFile *file)
+{
+ GFile *fuse_root;
+ char *fuse_path, *mount_path;
+ GMountInfo *mount_info;
+
+ fuse_root = ((GDaemonVfs *)vfs)->fuse_root;
+ if (g_file_has_prefix (file, fuse_root))
+ {
+ fuse_path = g_file_get_path (file);
+ mount_info = _g_daemon_vfs_get_mount_info_by_fuse_sync (fuse_path, &mount_path);
+ g_free (fuse_path);
+ if (mount_info)
+ {
+ g_object_unref (file);
+ /* TODO: Do we need to look at the prefix of the mount_spec? */
+ file = g_daemon_file_new (mount_info->mount_spec, mount_path);
+ g_free (mount_path);
+ g_mount_info_unref (mount_info);
+ }
+ }
+ return file;
+}
+
+static GFile *
+g_daemon_vfs_get_file_for_path (GVfs *vfs,
+ const char *path)
+{
+ GFile *file;
+
+ file = g_vfs_get_file_for_path (G_DAEMON_VFS (vfs)->wrapped_vfs, path);
+ file = convert_fuse_path (vfs, file);
+ return file;
+}
+
+static GFile *
+g_daemon_vfs_get_file_for_uri (GVfs *vfs,
+ const char *uri)
+{
+ GDaemonVfs *daemon_vfs;
+ GFile *file;
+ GMountSpec *spec;
+ char *path;
+
+ daemon_vfs = G_DAEMON_VFS (vfs);
+
+ if (g_ascii_strncasecmp (uri, "file:", 5) == 0)
+ {
+ path = g_filename_from_uri (uri, NULL, NULL);
+
+ if (path == NULL)
+ /* Dummy file */
+ return g_vfs_get_file_for_uri (G_DAEMON_VFS (vfs)->wrapped_vfs, uri);
+
+ file = g_daemon_vfs_get_file_for_path (vfs, path);
+ g_free (path);
+ return file;
+ }
+
+ if (get_mountspec_from_uri (daemon_vfs, uri, &spec, &path))
+ {
+ file = g_daemon_file_new (spec, path);
+ g_mount_spec_unref (spec);
+ g_free (path);
+ return file;
+ }
+
+ /* Dummy file */
+ return g_vfs_get_file_for_uri (G_DAEMON_VFS (vfs)->wrapped_vfs, uri);
+}
+
+GMountSpec *
+_g_daemon_vfs_get_mount_spec_for_path (GMountSpec *spec,
+ const char *path,
+ const char *new_path)
+{
+ const char *type;
+ GVfsUriMapper *mapper;
+ GMountSpec *new_spec;
+
+ type = g_mount_spec_get_type (spec);
+
+ if (type == NULL)
+ return g_mount_spec_ref (spec);
+
+ new_spec = NULL;
+ mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
+ if (mapper)
+ {
+ GVfsUriMountInfo info, *new_info;
+ info.keys = spec->items;
+ info.path = (char *)path;
+ new_info = g_vfs_uri_mapper_get_mount_info_for_path (mapper, &info, new_path);
+ if (new_info != NULL)
+ {
+ new_spec = g_mount_spec_new_from_data (new_info->keys, NULL);
+ /* We took over ownership of parts of new_info, custom free: */
+ g_free (new_info->path);
+ g_free (new_info);
+ }
+ }
+
+ if (new_spec == NULL)
+ new_spec = g_mount_spec_ref (spec);
+
+ return new_spec;
+}
+
+char *
+_g_daemon_vfs_get_uri_for_mountspec (GMountSpec *spec,
+ char *path,
+ gboolean allow_utf8)
+{
+ char *uri;
+ const char *type;
+ GVfsUriMapper *mapper;
+
+ type = g_mount_spec_get_type (spec);
+ if (type == NULL)
+ {
+ GString *string = g_string_new ("unknown://");
+ if (path)
+ g_string_append_uri_escaped (string,
+ path,
+ "!$&'()*+,;=:@/",
+ allow_utf8);
+
+ return g_string_free (string, FALSE);
+ }
+
+ uri = NULL;
+ mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
+ if (mapper)
+ {
+ GVfsUriMountInfo info;
+ info.keys = spec->items;
+ info.path = path;
+ uri = g_vfs_uri_mapper_to_uri (mapper, &info, allow_utf8);
+ }
+
+ if (uri == NULL)
+ {
+ GDecodedUri decoded;
+ MountableInfo *mountable;
+ const char *port;
+ gboolean free_host;
+
+ memset (&decoded, 0, sizeof (decoded));
+ decoded.port = -1;
+
+ mountable = get_mountable_info_for_type (the_vfs, type);
+
+ if (mountable)
+ decoded.scheme = mountable->scheme;
+ else
+ decoded.scheme = (char *)type;
+ decoded.host = (char *)g_mount_spec_get (spec, "host");
+ free_host = FALSE;
+ if (mountable && mountable->host_is_inet && decoded.host != NULL && strchr (decoded.host, ':') != NULL)
+ {
+ free_host = TRUE;
+ decoded.host = g_strconcat ("[", decoded.host, "]", NULL);
+ }
+
+ decoded.userinfo = (char *)g_mount_spec_get (spec, "user");
+ port = g_mount_spec_get (spec, "port");
+ if (port != NULL)
+ decoded.port = atoi (port);
+
+ if (path == NULL)
+ decoded.path = "/";
+ else
+ decoded.path = path;
+
+ decoded.query = (char *)g_mount_spec_get (spec, "query");
+ decoded.fragment = (char *)g_mount_spec_get (spec, "fragment");
+
+ uri = g_vfs_encode_uri (&decoded, FALSE);
+
+ if (free_host)
+ g_free (decoded.host);
+ }
+
+ return uri;
+}
+
+const char *
+_g_daemon_vfs_mountspec_get_uri_scheme (GMountSpec *spec)
+{
+ const char *type, *scheme;
+ GVfsUriMapper *mapper;
+ MountableInfo *mountable;
+
+ type = g_mount_spec_get_type (spec);
+ mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
+
+ scheme = NULL;
+ if (mapper)
+ {
+ GVfsUriMountInfo info;
+
+ info.keys = spec->items;
+ info.path = "/";
+
+ scheme = g_vfs_uri_mapper_to_uri_scheme (mapper, &info);
+ }
+
+ if (scheme == NULL)
+ {
+ mountable = get_mountable_info_for_type (the_vfs, type);
+ if (mountable)
+ scheme = mountable->scheme;
+ else
+ scheme = type;
+ }
+
+ return scheme;
+}
+
+static int
+find_string (GPtrArray *array, const char *find_me)
+{
+ int i;
+
+ g_return_val_if_fail (find_me != NULL, -1);
+
+ for (i = 0; i < array->len; ++i)
+ {
+ if (strcmp (g_ptr_array_index (array, i), find_me) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+
+static void
+fill_mountable_info (GDaemonVfs *vfs)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ DBusMessageIter iter, array_iter, struct_iter;
+ MountableInfo *info;
+ GPtrArray *infos, *uri_schemes;
+ gint i, count;
+
+ message = dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
+ G_VFS_DBUS_MOUNTTRACKER_PATH,
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
+ G_VFS_DBUS_MOUNTTRACKER_OP_LIST_MOUNTABLE_INFO);
+
+ if (message == NULL)
+ _g_dbus_oom ();
+
+ dbus_message_set_auto_start (message, TRUE);
+
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (vfs->async_bus,
+ message,
+ G_VFS_DBUS_TIMEOUT_MSECS,
+ &error);
+ dbus_message_unref (message);
+
+ if (dbus_error_is_set (&error))
+ {
+ dbus_error_free (&error);
+ return;
+ }
+
+ if (reply == NULL)
+ _g_dbus_oom ();
+
+ dbus_message_iter_init (reply, &iter);
+
+ dbus_message_iter_recurse (&iter, &array_iter);
+
+ infos = g_ptr_array_new ();
+ uri_schemes = g_ptr_array_new ();
+ count = 0;
+ do
+ {
+ char *type, *scheme, **scheme_aliases;
+ int scheme_aliases_len;
+ gint32 default_port;
+ dbus_bool_t host_is_inet;
+
+ if (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_STRUCT)
+ break;
+
+ dbus_message_iter_recurse (&array_iter, &struct_iter);
+
+ if (!_g_dbus_message_iter_get_args (&struct_iter, NULL,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_STRING, &scheme,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &scheme_aliases, &scheme_aliases_len,
+ DBUS_TYPE_INT32, &default_port,
+ DBUS_TYPE_BOOLEAN, &host_is_inet,
+ 0))
+ break;
+
+ info = g_new0 (MountableInfo, 1);
+ info->type = g_strdup (type);
+ if (*scheme != 0)
+ {
+ info->scheme = g_strdup (scheme);
+ if (find_string (uri_schemes, scheme) == -1)
+ g_ptr_array_add (uri_schemes, g_strdup (scheme));
+ }
+
+ if (scheme_aliases_len > 0)
+ {
+ info->scheme_aliases = g_new (char *, scheme_aliases_len + 1);
+ for (i = 0; i < scheme_aliases_len; i++)
+ {
+ info->scheme_aliases[i] = g_strdup (scheme_aliases[i]);
+ if (find_string (uri_schemes, scheme_aliases[i]) == -1)
+ g_ptr_array_add (uri_schemes, g_strdup (scheme_aliases[i]));
+ }
+ info->scheme_aliases[scheme_aliases_len] = NULL;
+ }
+
+ info->default_port = default_port;
+ info->host_is_inet = host_is_inet;
+
+ g_ptr_array_add (infos, info);
+
+ g_strfreev (scheme_aliases);
+ }
+ while (dbus_message_iter_next (&array_iter));
+
+ dbus_message_unref (reply);
+
+ g_ptr_array_add (uri_schemes, NULL);
+ g_ptr_array_add (infos, NULL);
+ vfs->mountable_info = (MountableInfo **)g_ptr_array_free (infos, FALSE);
+ vfs->supported_uri_schemes = (char **)g_ptr_array_free (uri_schemes, FALSE);
+}
+
+
+static const gchar * const *
+g_daemon_vfs_get_supported_uri_schemes (GVfs *vfs)
+{
+ return (const gchar * const *) G_DAEMON_VFS (vfs)->supported_uri_schemes;
+}
+
+static GMountInfo *
+lookup_mount_info_in_cache_locked (GMountSpec *spec,
+ const char *path)
+{
+ GMountInfo *info;
+ GList *l;
+
+ info = NULL;
+ for (l = the_vfs->mount_cache; l != NULL; l = l->next)
+ {
+ GMountInfo *mount_info = l->data;
+
+ if (g_mount_spec_match_with_path (mount_info->mount_spec, spec, path))
+ {
+ info = g_mount_info_ref (mount_info);
+ break;
+ }
+ }
+
+ return info;
+}
+
+static GMountInfo *
+lookup_mount_info_in_cache (GMountSpec *spec,
+ const char *path)
+{
+ GMountInfo *info;
+
+ G_LOCK (mount_cache);
+ info = lookup_mount_info_in_cache_locked (spec, path);
+ G_UNLOCK (mount_cache);
+
+ return info;
+}
+
+static GMountInfo *
+lookup_mount_info_by_fuse_path_in_cache (const char *fuse_path,
+ char **mount_path)
+{
+ GMountInfo *info;
+ GList *l;
+
+ G_LOCK (mount_cache);
+ info = NULL;
+ for (l = the_vfs->mount_cache; l != NULL; l = l->next)
+ {
+ GMountInfo *mount_info = l->data;
+
+ if (mount_info->fuse_mountpoint != NULL &&
+ g_str_has_prefix (fuse_path, mount_info->fuse_mountpoint))
+ {
+ int len = strlen (mount_info->fuse_mountpoint);
+ if (fuse_path[len] == 0 ||
+ fuse_path[len] == '/')
+ {
+ if (fuse_path[len] == 0)
+ *mount_path = g_strdup ("/");
+ else
+ *mount_path = g_strdup (fuse_path + len);
+ info = g_mount_info_ref (mount_info);
+ break;
+ }
+ }
+ }
+ G_UNLOCK (mount_cache);
+
+ return info;
+}
+
+
+void
+_g_daemon_vfs_invalidate_dbus_id (const char *dbus_id)
+{
+ GList *l, *next;
+
+ G_LOCK (mount_cache);
+ for (l = the_vfs->mount_cache; l != NULL; l = next)
+ {
+ GMountInfo *mount_info = l->data;
+ next = l->next;
+
+ if (strcmp (mount_info->dbus_id, dbus_id) == 0)
+ {
+ the_vfs->mount_cache = g_list_delete_link (the_vfs->mount_cache, l);
+ g_mount_info_unref (mount_info);
+ }
+ }
+
+ G_UNLOCK (mount_cache);
+}
+
+
+static GMountInfo *
+handler_lookup_mount_reply (DBusMessage *reply,
+ GError **error)
+{
+ DBusError derror;
+ GMountInfo *info;
+ DBusMessageIter iter;
+ GList *l;
+ gboolean in_cache;
+
+
+ if (_g_error_from_message (reply, error))
+ return NULL;
+
+ dbus_error_init (&derror);
+ dbus_message_iter_init (reply, &iter);
+
+ info = g_mount_info_from_dbus (&iter);
+ if (info == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Error while getting mount info: %s"),
+ "Invalid reply");
+ return NULL;
+ }
+
+ G_LOCK (mount_cache);
+
+ in_cache = FALSE;
+ /* Already in cache from other thread? */
+ for (l = the_vfs->mount_cache; l != NULL; l = l->next)
+ {
+ GMountInfo *cached_info = l->data;
+
+ if (g_mount_info_equal (info, cached_info))
+ {
+ in_cache = TRUE;
+ g_mount_info_unref (info);
+ info = g_mount_info_ref (cached_info);
+ break;
+ }
+ }
+
+ /* No, lets add it to the cache */
+ if (!in_cache)
+ the_vfs->mount_cache = g_list_prepend (the_vfs->mount_cache, g_mount_info_ref (info));
+
+ G_UNLOCK (mount_cache);
+
+ return info;
+}
+
+typedef struct {
+ GMountInfoLookupCallback callback;
+ gpointer user_data;
+} GetMountInfoData;
+
+static void
+async_get_mount_info_response (DBusMessage *reply,
+ GError *io_error,
+ void *_data)
+{
+ GetMountInfoData *data = _data;
+ GMountInfo *info;
+ GError *error;
+
+ if (reply == NULL)
+ data->callback (NULL, data->user_data, io_error);
+ else
+ {
+ error = NULL;
+ info = handler_lookup_mount_reply (reply, &error);
+
+ data->callback (info, data->user_data, error);
+
+ if (info)
+ g_mount_info_unref (info);
+
+ if (error)
+ g_error_free (error);
+ }
+
+ g_free (data);
+}
+
+void
+_g_daemon_vfs_get_mount_info_async (GMountSpec *spec,
+ const char *path,
+ GMountInfoLookupCallback callback,
+ gpointer user_data)
+{
+ GMountInfo *info;
+ GetMountInfoData *data;
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ info = lookup_mount_info_in_cache (spec, path);
+
+ if (info != NULL)
+ {
+ callback (info, user_data, NULL);
+ g_mount_info_unref (info);
+ return;
+ }
+
+ message =
+ dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
+ G_VFS_DBUS_MOUNTTRACKER_PATH,
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
+ G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT);
+ dbus_message_set_auto_start (message, TRUE);
+
+ dbus_message_iter_init_append (message, &iter);
+ g_mount_spec_to_dbus_with_path (&iter, spec, path);
+
+ data = g_new0 (GetMountInfoData, 1);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ _g_dbus_connection_call_async (the_vfs->async_bus, message, G_VFS_DBUS_TIMEOUT_MSECS,
+ async_get_mount_info_response,
+ data);
+
+ dbus_message_unref (message);
+}
+
+
+GMountInfo *
+_g_daemon_vfs_get_mount_info_sync (GMountSpec *spec,
+ const char *path,
+ GError **error)
+{
+ GMountInfo *info;
+ DBusConnection *conn;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter;
+ DBusError derror;
+
+ info = lookup_mount_info_in_cache (spec, path);
+
+ if (info != NULL)
+ return info;
+
+ conn = _g_dbus_connection_get_sync (NULL, error);
+ if (conn == NULL)
+ return NULL;
+
+ message =
+ dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
+ G_VFS_DBUS_MOUNTTRACKER_PATH,
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
+ G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT);
+ dbus_message_set_auto_start (message, TRUE);
+
+ dbus_message_iter_init_append (message, &iter);
+ g_mount_spec_to_dbus_with_path (&iter, spec, path);
+
+ dbus_error_init (&derror);
+ reply = dbus_connection_send_with_reply_and_block (conn, message, -1, &derror);
+ dbus_message_unref (message);
+
+ if (!reply)
+ {
+ _g_error_from_dbus (&derror, error);
+ dbus_error_free (&derror);
+ return NULL;
+ }
+
+ info = handler_lookup_mount_reply (reply, error);
+
+ dbus_message_unref (reply);
+
+ return info;
+}
+
+GMountInfo *
+_g_daemon_vfs_get_mount_info_by_fuse_sync (const char *fuse_path,
+ char **mount_path)
+{
+ GMountInfo *info;
+ DBusConnection *conn;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter;
+ DBusError derror;
+ int len;
+
+ info = lookup_mount_info_by_fuse_path_in_cache (fuse_path,
+ mount_path);
+ if (info != NULL)
+ return info;
+
+ conn = _g_dbus_connection_get_sync (NULL, NULL);
+ if (conn == NULL)
+ return NULL;
+
+ message =
+ dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
+ G_VFS_DBUS_MOUNTTRACKER_PATH,
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
+ G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT_BY_FUSE_PATH);
+ dbus_message_set_auto_start (message, TRUE);
+
+ dbus_message_iter_init_append (message, &iter);
+ _g_dbus_message_iter_append_cstring (&iter, fuse_path);
+
+ dbus_error_init (&derror);
+ reply = dbus_connection_send_with_reply_and_block (conn, message, -1, &derror);
+ dbus_message_unref (message);
+ if (!reply)
+ {
+ dbus_error_free (&derror);
+ return NULL;
+ }
+
+ info = handler_lookup_mount_reply (reply, NULL);
+ dbus_message_unref (reply);
+
+ if (info)
+ {
+ if (info->fuse_mountpoint)
+ {
+ len = strlen (info->fuse_mountpoint);
+ if (fuse_path[len] == 0)
+ *mount_path = g_strdup ("/");
+ else
+ *mount_path = g_strdup (fuse_path + len);
+ }
+ else
+ {
+ /* This could happen if we race with the gvfs fuse mount
+ * at startup of gvfsd... */
+ g_mount_info_unref (info);
+ info = NULL;
+ }
+ }
+
+
+ return info;
+}
+
+static GFile *
+g_daemon_vfs_parse_name (GVfs *vfs,
+ const char *parse_name)
+{
+ GFile *file;
+
+ if (g_path_is_absolute (parse_name) ||
+ *parse_name == '~')
+ {
+ file = g_vfs_parse_name (G_DAEMON_VFS (vfs)->wrapped_vfs, parse_name);
+ file = convert_fuse_path (vfs, file);
+ }
+ else
+ {
+ file = g_daemon_vfs_get_file_for_uri (vfs, parse_name);
+ }
+
+ return file;
+}
+
+DBusConnection *
+_g_daemon_vfs_get_async_bus (void)
+{
+ return the_vfs->async_bus;
+}
+
+static gboolean
+g_daemon_vfs_is_active (GVfs *vfs)
+{
+ GDaemonVfs *daemon_vfs = G_DAEMON_VFS (vfs);
+ return daemon_vfs->async_bus != NULL;
+}
+
+static void
+g_daemon_vfs_class_finalize (GDaemonVfsClass *klass)
+{
+}
+
+static void
+g_daemon_vfs_class_init (GDaemonVfsClass *class)
+{
+ GObjectClass *object_class;
+ GVfsClass *vfs_class;
+
+ object_class = (GObjectClass *) class;
+
+ g_daemon_vfs_parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = g_daemon_vfs_finalize;
+
+ vfs_class = G_VFS_CLASS (class);
+
+ vfs_class->is_active = g_daemon_vfs_is_active;
+ vfs_class->get_file_for_path = g_daemon_vfs_get_file_for_path;
+ vfs_class->get_file_for_uri = g_daemon_vfs_get_file_for_uri;
+ vfs_class->get_supported_uri_schemes = g_daemon_vfs_get_supported_uri_schemes;
+ vfs_class->parse_name = g_daemon_vfs_parse_name;
+}
+
+/* Module API */
+
+void g_vfs_uri_mapper_smb_register (GIOModule *module);
+void g_vfs_uri_mapper_http_register (GIOModule *module);
+void g_vfs_uri_mapper_sftp_register (GIOModule *module);
+
+void
+g_io_module_load (GIOModule *module)
+{
+ /* This is so that system daemons can use gio
+ * without spawning private dbus instances.
+ * See bug 526454.
+ */
+ if (g_getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
+ return;
+
+ /* Make this module resident so that we ground the common
+ * library. If that is unloaded we could get into all kinds
+ * of strange situations. This is safe to do even if we loaded
+ * some other common-using module first as all modules are loaded
+ * before any are freed.
+ */
+ g_type_module_use (G_TYPE_MODULE (module));
+
+ g_daemon_vfs_register_type (G_TYPE_MODULE (module));
+ g_daemon_volume_monitor_register_types (G_TYPE_MODULE (module));
+
+ /* We implement GLoadableIcon only on client side.
+ see comment in common/giconvfs.c */
+ _g_vfs_icon_add_loadable_interface ();
+
+ g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
+ G_TYPE_DAEMON_VFS,
+ "gvfs",
+ 10);
+
+ g_vfs_uri_mapper_register (module);
+ g_vfs_uri_mapper_smb_register (module);
+ g_vfs_uri_mapper_http_register (module);
+}
+
+void
+g_io_module_unload (GIOModule *module)
+{
+}