diff options
Diffstat (limited to 'trunk/monitor/proxy/gproxymount.c')
-rw-r--r-- | trunk/monitor/proxy/gproxymount.c | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/trunk/monitor/proxy/gproxymount.c b/trunk/monitor/proxy/gproxymount.c new file mode 100644 index 00000000..18259f53 --- /dev/null +++ b/trunk/monitor/proxy/gproxymount.c @@ -0,0 +1,665 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 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: David Zeuthen <davidz@redhat.com> + */ + +#include <config.h> + +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <gio/gio.h> + +#include <gdbusutils.h> + +#include "gproxyvolumemonitor.h" +#include "gproxymount.h" +#include "gproxyvolume.h" + +/* Protects all fields of GProxyMount that can change */ +G_LOCK_DEFINE_STATIC(proxy_mount); + +struct _GProxyMount { + GObject parent; + + GProxyVolumeMonitor *volume_monitor; + + char *id; + char *name; + char *uuid; + char *volume_id; + gboolean can_unmount; + char **x_content_types; + GFile *root; + GIcon *icon; +}; + +static void g_proxy_mount_mount_iface_init (GMountIface *iface); + +#define _G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ + (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ +} +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyMount, g_proxy_mount, G_TYPE_OBJECT, 0, + _G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_MOUNT, + g_proxy_mount_mount_iface_init)) + +static void +g_proxy_mount_finalize (GObject *object) +{ + GProxyMount *mount; + + mount = G_PROXY_MOUNT (object); + + g_free (mount->id); + g_free (mount->name); + g_free (mount->uuid); + g_free (mount->volume_id); + g_strfreev (mount->x_content_types); + if (mount->icon != NULL) + g_object_unref (mount->icon); + if (mount->root != NULL) + g_object_unref (mount->root); + + if (mount->volume_monitor != NULL) + g_object_unref (mount->volume_monitor); + + if (G_OBJECT_CLASS (g_proxy_mount_parent_class)->finalize) + (*G_OBJECT_CLASS (g_proxy_mount_parent_class)->finalize) (object); +} + +static void +g_proxy_mount_class_init (GProxyMountClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_proxy_mount_finalize; +} + +static void +g_proxy_mount_class_finalize (GProxyMountClass *klass) +{ +} + +static void +g_proxy_mount_init (GProxyMount *proxy_mount) +{ +} + +GProxyMount * +g_proxy_mount_new (GProxyVolumeMonitor *volume_monitor) +{ + GProxyMount *mount; + mount = g_object_new (G_TYPE_PROXY_MOUNT, NULL); + mount->volume_monitor = g_object_ref (volume_monitor); + g_object_set_data (G_OBJECT (mount), + "g-proxy-mount-volume-monitor-name", + (gpointer) g_type_name (G_TYPE_FROM_INSTANCE (volume_monitor))); + return mount; +} + +gboolean +g_proxy_mount_has_mount_path (GProxyMount *mount, const char *mount_path) +{ + char *path; + gboolean result; + result = FALSE; + path = g_file_get_path (mount->root); + if (path != NULL) + { + if (strcmp (path, mount_path) == 0) + result = TRUE; + g_free (path); + } + return result; +} + +/* string id + * string name + * string gicon_data + * string uuid + * string root_uri + * boolean can-unmount + * string volume-id + * array:string x-content-types + */ + +void +g_proxy_mount_update (GProxyMount *mount, + DBusMessageIter *iter) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_x_content_types; + const char *id; + const char *name; + const char *gicon_data; + const char *uuid; + const char *root_uri; + dbus_bool_t can_unmount; + const char *volume_id; + GPtrArray *x_content_types; + + dbus_message_iter_recurse (iter, &iter_struct); + dbus_message_iter_get_basic (&iter_struct, &id); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &name); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &gicon_data); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &uuid); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &root_uri); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &can_unmount); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &volume_id); + dbus_message_iter_next (&iter_struct); + + x_content_types = g_ptr_array_new (); + dbus_message_iter_recurse (&iter_struct, &iter_x_content_types); + while (dbus_message_iter_get_arg_type (&iter_x_content_types) != DBUS_TYPE_INVALID) + { + const char *x_content_type; + dbus_message_iter_get_basic (&iter_x_content_types, &x_content_type); + dbus_message_iter_next (&iter_x_content_types); + g_ptr_array_add (x_content_types, (gpointer) x_content_type); + } + g_ptr_array_add (x_content_types, NULL); + dbus_message_iter_next (&iter_struct); + + if (mount->id != NULL && strcmp (mount->id, id) != 0) + { + g_warning ("id mismatch during update of mount"); + goto out; + } + + if (strlen (name) == 0) + name = NULL; + if (strlen (uuid) == 0) + uuid = NULL; + + /* out with the old */ + g_free (mount->id); + g_free (mount->name); + g_free (mount->uuid); + g_free (mount->volume_id); + if (mount->icon != NULL) + g_object_unref (mount->icon); + g_strfreev (mount->x_content_types); + if (mount->root != NULL) + g_object_unref (mount->root); + + /* in with the new */ + mount->id = g_strdup (id); + mount->name = g_strdup (name); + if (*gicon_data == 0) + mount->icon = NULL; + else + mount->icon = g_icon_new_for_string (gicon_data, NULL); + mount->uuid = g_strdup (uuid); + mount->root = g_file_new_for_uri (root_uri); + mount->can_unmount = can_unmount; + mount->volume_id = g_strdup (volume_id); + mount->x_content_types = g_strdupv ((char **) x_content_types->pdata); + + out: + g_ptr_array_free (x_content_types, TRUE); +} + +const char * +g_proxy_mount_get_id (GProxyMount *mount) +{ + return mount->id; +} + +static GFile * +g_proxy_mount_get_root (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GFile *root; + + G_LOCK (proxy_mount); + root = proxy_mount->root != NULL ? g_object_ref (proxy_mount->root) : NULL; + G_UNLOCK (proxy_mount); + return root; +} + +static GIcon * +g_proxy_mount_get_icon (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GIcon *icon; + + G_LOCK (proxy_mount); + icon = proxy_mount->icon != NULL ? g_object_ref (proxy_mount->icon) : NULL; + G_UNLOCK (proxy_mount); + return icon; +} + +static char * +g_proxy_mount_get_uuid (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + char *uuid; + + G_LOCK (proxy_mount); + uuid = g_strdup (proxy_mount->uuid); + G_UNLOCK (proxy_mount); + return uuid; +} + +static char * +g_proxy_mount_get_name (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + char *name; + + G_LOCK (proxy_mount); + name = g_strdup (proxy_mount->name); + G_UNLOCK (proxy_mount); + + return name; +} + +static GDrive * +g_proxy_mount_get_drive (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GProxyVolume *volume; + GDrive *drive; + + G_LOCK (proxy_mount); + volume = NULL; + if (proxy_mount->volume_id != NULL && strlen (proxy_mount->volume_id) > 0) + volume = g_proxy_volume_monitor_get_volume_for_id (proxy_mount->volume_monitor, + proxy_mount->volume_id); + G_UNLOCK (proxy_mount); + + drive = NULL; + if (volume != NULL) + { + drive = g_volume_get_drive (G_VOLUME (volume)); + g_object_unref (volume); + } + + return drive; +} + +static GVolume * +g_proxy_mount_get_volume (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GProxyVolume *volume; + + G_LOCK (proxy_mount); + volume = NULL; + if (proxy_mount->volume_id != NULL && strlen (proxy_mount->volume_id) > 0) + volume = g_proxy_volume_monitor_get_volume_for_id (proxy_mount->volume_monitor, + proxy_mount->volume_id); + G_UNLOCK (proxy_mount); + + return volume != NULL ? G_VOLUME (volume) : NULL; +} + +static gboolean +g_proxy_mount_can_unmount (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + gboolean res; + + G_LOCK (proxy_mount); + res = proxy_mount->can_unmount; + G_UNLOCK (proxy_mount); + + return res; +} + +static gboolean +g_proxy_mount_can_eject (GMount *mount) +{ + GDrive *drive; + gboolean can_eject; + + can_eject = FALSE; + drive = g_proxy_mount_get_drive (mount); + if (drive != NULL) + { + can_eject = g_drive_can_eject (drive); + g_object_unref (drive); + } + + return can_eject; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; +} EjectWrapperOp; + +static void +eject_wrapper_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EjectWrapperOp *data = user_data; + data->callback (data->object, res, data->user_data); + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_mount_eject (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDrive *drive; + + drive = g_proxy_mount_get_drive (mount); + + if (drive != NULL) + { + EjectWrapperOp *data; + data = g_new0 (EjectWrapperOp, 1); + data->object = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + g_drive_eject (drive, flags, cancellable, eject_wrapper_callback, data); + g_object_unref (drive); + } +} + +static gboolean +g_proxy_mount_eject_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GDrive *drive; + gboolean res; + + res = TRUE; + + drive = g_proxy_mount_get_drive (mount); + + if (drive != NULL) + { + res = g_drive_eject_finish (drive, result, error); + g_object_unref (drive); + } + return res; +} + +typedef struct { + GProxyMount *mount; + GAsyncReadyCallback callback; + gpointer user_data; + + gchar *cancellation_id; + GCancellable *cancellable; + gulong cancelled_handler_id; +} DBusOp; + +static void +cancel_operation_reply_cb (DBusMessage *reply, + GError *error, + gpointer user_data) +{ + if (error != NULL) + { + g_warning ("Error from CancelOperation(): %s", error->message); + } +} + +static void +operation_cancelled (GCancellable *cancellable, + gpointer user_data) +{ + DBusOp *data = user_data; + GSimpleAsyncResult *simple; + DBusConnection *connection; + DBusMessage *message; + const char *name; + + G_LOCK (proxy_mount); + + simple = g_simple_async_result_new_error (G_OBJECT (data->mount), + data->callback, + data->user_data, + G_IO_ERROR, + G_IO_ERROR_CANCELLED, + _("Operation was cancelled")); + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); + + /* Now tell the remote volume monitor that the op has been cancelled */ + connection = g_proxy_volume_monitor_get_dbus_connection (data->mount->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (data->mount->volume_monitor); + message = dbus_message_new_method_call (name, + "/org/gtk/Private/RemoteVolumeMonitor", + "org.gtk.Private.RemoteVolumeMonitor", + "CancelOperation"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(data->cancellation_id), + DBUS_TYPE_INVALID); + + G_UNLOCK (proxy_mount); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) cancel_operation_reply_cb, + NULL); + dbus_message_unref (message); + dbus_connection_unref (connection); +} + +static void +unmount_cb (DBusMessage *reply, + GError *error, + DBusOp *data) +{ + if (data->cancelled_handler_id > 0) + g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id); + + if (!g_cancellable_is_cancelled (data->cancellable)) + { + GSimpleAsyncResult *simple; + if (error != NULL) + simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), + data->callback, + data->user_data, + error); + else + simple = g_simple_async_result_new (G_OBJECT (data->mount), + data->callback, + data->user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + } + + g_object_unref (data->mount); + g_free (data->cancellation_id); + if (data->cancellable != NULL) + g_object_unref (data->cancellable); + g_free (data); +} + +static void +g_proxy_mount_unmount (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + DBusConnection *connection; + const char *name; + DBusMessage *message; + DBusOp *data; + dbus_uint32_t _flags = flags; + + G_LOCK (proxy_mount); + + if (g_cancellable_is_cancelled (cancellable)) + { + GSimpleAsyncResult *simple; + simple = g_simple_async_result_new_error (G_OBJECT (mount), + callback, + user_data, + G_IO_ERROR, + G_IO_ERROR_CANCELLED, + _("Operation was cancelled")); + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); + G_UNLOCK (proxy_mount); + goto out; + } + + data = g_new0 (DBusOp, 1); + data->mount = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + + if (cancellable != NULL) + { + data->cancellation_id = g_strdup_printf ("%p", cancellable); + data->cancellable = g_object_ref (cancellable); + data->cancelled_handler_id = g_signal_connect (data->cancellable, + "cancelled", + G_CALLBACK (operation_cancelled), + data); + } + else + { + data->cancellation_id = g_strdup (""); + } + + connection = g_proxy_volume_monitor_get_dbus_connection (proxy_mount->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (proxy_mount->volume_monitor); + + message = dbus_message_new_method_call (name, + "/org/gtk/Private/RemoteVolumeMonitor", + "org.gtk.Private.RemoteVolumeMonitor", + "MountUnmount"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(proxy_mount->id), + DBUS_TYPE_STRING, + &(data->cancellation_id), + DBUS_TYPE_UINT32, + &_flags, + DBUS_TYPE_INVALID); + G_UNLOCK (proxy_mount); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) unmount_cb, + data); + + dbus_message_unref (message); + dbus_connection_unref (connection); + out: + ; +} + +static gboolean +g_proxy_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + return TRUE; +} + +static void +g_proxy_mount_guess_content_type (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + /* TODO: handle force_rescan */ + simple = g_simple_async_result_new (G_OBJECT (mount), + callback, + user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static char ** +g_proxy_mount_guess_content_type_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + return g_strdupv (proxy_mount->x_content_types); +} + +static char ** +g_proxy_mount_guess_content_type_sync (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GError **error) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + /* TODO: handle force_rescan */ + return g_strdupv (proxy_mount->x_content_types); +} + +static void +g_proxy_mount_mount_iface_init (GMountIface *iface) +{ + iface->get_root = g_proxy_mount_get_root; + iface->get_name = g_proxy_mount_get_name; + iface->get_icon = g_proxy_mount_get_icon; + iface->get_uuid = g_proxy_mount_get_uuid; + iface->get_drive = g_proxy_mount_get_drive; + iface->get_volume = g_proxy_mount_get_volume; + iface->can_unmount = g_proxy_mount_can_unmount; + iface->can_eject = g_proxy_mount_can_eject; + iface->unmount = g_proxy_mount_unmount; + iface->unmount_finish = g_proxy_mount_unmount_finish; + iface->eject = g_proxy_mount_eject; + iface->eject_finish = g_proxy_mount_eject_finish; + iface->guess_content_type = g_proxy_mount_guess_content_type; + iface->guess_content_type_finish = g_proxy_mount_guess_content_type_finish; + iface->guess_content_type_sync = g_proxy_mount_guess_content_type_sync; +} + +void +g_proxy_mount_register (GIOModule *module) +{ + g_proxy_mount_register_type (G_TYPE_MODULE (module)); +} |