/* -*- 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * Author: David Zeuthen */ #include #include #include #include #include #include #include #include "gproxyvolumemonitor.h" #include "gproxyshadowmount.h" #include "gproxyvolume.h" static void signal_emit_in_idle (gpointer object, const char *signal_name, gpointer other_object); /* Protects all fields of GProxyShadowMount that can change */ G_LOCK_DEFINE_STATIC(proxy_shadow_mount); struct _GProxyShadowMount { GObject parent; GProxyVolumeMonitor *volume_monitor; GProxyVolume *volume; GMount *real_mount; gulong pre_unmount_signal_id; gboolean real_mount_shadowed; GFile *root; }; static void g_proxy_shadow_mount_mount_iface_init (GMountIface *iface); G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyShadowMount, g_proxy_shadow_mount, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_MOUNT, g_proxy_shadow_mount_mount_iface_init)) static void g_proxy_shadow_mount_finalize (GObject *object) { GProxyShadowMount *mount; mount = G_PROXY_SHADOW_MOUNT (object); g_proxy_shadow_mount_remove (mount); if (mount->real_mount != NULL) { g_object_unref (mount->real_mount); mount->real_mount = NULL; } if (mount->volume_monitor != NULL) g_object_unref (mount->volume_monitor); if (mount->volume != NULL) g_object_unref (mount->volume); if (mount->root != NULL) g_object_unref (mount->root); if (G_OBJECT_CLASS (g_proxy_shadow_mount_parent_class)->finalize) (*G_OBJECT_CLASS (g_proxy_shadow_mount_parent_class)->finalize) (object); } static void g_proxy_shadow_mount_class_init (GProxyShadowMountClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = g_proxy_shadow_mount_finalize; } static void g_proxy_shadow_mount_class_finalize (GProxyShadowMountClass *klass) { } static void g_proxy_shadow_mount_init (GProxyShadowMount *proxy_shadow_mount) { } static void real_mount_pre_unmount_cb (GMount *real_mount, GProxyShadowMount *shadow_mount) { g_signal_emit_by_name (shadow_mount, "pre-unmount", 0); g_signal_emit_by_name (shadow_mount->volume_monitor, "mount-pre-unmount", shadow_mount); } void g_proxy_shadow_mount_remove (GProxyShadowMount *mount) { if (mount->real_mount_shadowed) { g_mount_unshadow (mount->real_mount); signal_emit_in_idle (mount->real_mount, "changed", NULL); signal_emit_in_idle (mount->volume_monitor, "mount-changed", mount->real_mount); mount->real_mount_shadowed = FALSE; if (mount->pre_unmount_signal_id != 0) { g_signal_handler_disconnect (mount->real_mount, mount->pre_unmount_signal_id); mount->pre_unmount_signal_id = 0; } } } GProxyShadowMount * g_proxy_shadow_mount_new (GProxyVolumeMonitor *volume_monitor, GProxyVolume *volume, GMount *real_mount) { GProxyShadowMount *mount; GFile *activation_root; mount = NULL; activation_root = g_volume_get_activation_root (G_VOLUME (volume)); if (activation_root == NULL) { g_warning ("Cannot construct a GProxyShadowMount object for a volume without an activation root"); goto out; } mount = g_object_new (G_TYPE_PROXY_SHADOW_MOUNT, NULL); mount->volume_monitor = g_object_ref (volume_monitor); mount->volume = g_object_ref (volume); mount->real_mount = g_object_ref (real_mount); mount->real_mount_shadowed = TRUE; mount->root = activation_root; g_mount_shadow (mount->real_mount); signal_emit_in_idle (mount->real_mount, "changed", NULL); signal_emit_in_idle (mount->volume_monitor, "mount-changed", mount->real_mount); mount->pre_unmount_signal_id = g_signal_connect (mount->real_mount, "pre-unmount", G_CALLBACK (real_mount_pre_unmount_cb), mount); g_object_set_data (G_OBJECT (mount), "g-proxy-shadow-mount-volume-monitor-name", (gpointer) g_type_name (G_TYPE_FROM_INSTANCE (volume_monitor))); out: return mount; } gboolean g_proxy_shadow_mount_has_mount_path (GProxyShadowMount *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; } static GFile * g_proxy_shadow_mount_get_root (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); GFile *root; G_LOCK (proxy_shadow_mount); root = g_object_ref (proxy_shadow_mount->root); G_UNLOCK (proxy_shadow_mount); return root; } static GIcon * g_proxy_shadow_mount_get_icon (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); GIcon *icon; G_LOCK (proxy_shadow_mount); icon = g_volume_get_icon (G_VOLUME (proxy_shadow_mount->volume)); G_UNLOCK (proxy_shadow_mount); return icon; } static GIcon * g_proxy_shadow_mount_get_symbolic_icon (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); GIcon *icon; G_LOCK (proxy_shadow_mount); icon = g_volume_get_symbolic_icon (G_VOLUME (proxy_shadow_mount->volume)); G_UNLOCK (proxy_shadow_mount); return icon; } static char * g_proxy_shadow_mount_get_uuid (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); char *uuid; G_LOCK (proxy_shadow_mount); uuid = g_mount_get_uuid (G_MOUNT (proxy_shadow_mount->real_mount)); G_UNLOCK (proxy_shadow_mount); return uuid; } static char * g_proxy_shadow_mount_get_name (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); char *name; G_LOCK (proxy_shadow_mount); name = g_volume_get_name (G_VOLUME (proxy_shadow_mount->volume)); G_UNLOCK (proxy_shadow_mount); return name; } static GDrive * g_proxy_shadow_mount_get_drive (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); GDrive *drive; G_LOCK (proxy_shadow_mount); drive = g_mount_get_drive (G_MOUNT (proxy_shadow_mount->real_mount)); G_UNLOCK (proxy_shadow_mount); return drive; } static GVolume * g_proxy_shadow_mount_get_volume (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); GVolume *volume; G_LOCK (proxy_shadow_mount); volume = G_VOLUME (g_object_ref (proxy_shadow_mount->volume)); G_UNLOCK (proxy_shadow_mount); return volume; } static gboolean g_proxy_shadow_mount_can_unmount (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); gboolean res; G_LOCK (proxy_shadow_mount); res = g_mount_can_unmount (G_MOUNT (proxy_shadow_mount->real_mount)); G_UNLOCK (proxy_shadow_mount); return res; } static gboolean g_proxy_shadow_mount_can_eject (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); gboolean res; G_LOCK (proxy_shadow_mount); res = g_volume_can_eject (G_VOLUME (proxy_shadow_mount->volume)); G_UNLOCK (proxy_shadow_mount); return res; } typedef struct { GObject *object; GAsyncReadyCallback callback; gpointer user_data; } AsyncWrapperOp; static void async_wrapper_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { AsyncWrapperOp *data = user_data; data->callback (data->object, res, data->user_data); g_object_unref (data->object); g_free (data); } static AsyncWrapperOp * setup_async_wrapper (GMount *mount, GAsyncReadyCallback callback, gpointer user_data) { AsyncWrapperOp *data; data = g_new0 (AsyncWrapperOp, 1); data->object = G_OBJECT (g_object_ref (mount)); data->callback = callback; data->user_data = user_data; return data; } static void g_proxy_shadow_mount_eject_with_operation (GMount *mount, GMountUnmountFlags flags, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); AsyncWrapperOp *data; data = setup_async_wrapper (mount, callback, user_data); G_LOCK (proxy_shadow_mount); g_volume_eject_with_operation (G_VOLUME (proxy_shadow_mount->volume), flags, mount_operation, cancellable, async_wrapper_callback, data); G_UNLOCK (proxy_shadow_mount); } static gboolean g_proxy_shadow_mount_eject_with_operation_finish (GMount *mount, GAsyncResult *result, GError **error) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); gboolean res; G_LOCK (proxy_shadow_mount); res = g_volume_eject_with_operation_finish (G_VOLUME (proxy_shadow_mount->volume), result, error); G_UNLOCK (proxy_shadow_mount); return res; } static void g_proxy_shadow_mount_unmount_with_operation (GMount *mount, GMountUnmountFlags flags, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); AsyncWrapperOp *data; data = setup_async_wrapper (mount, callback, user_data); g_mount_unmount_with_operation (proxy_shadow_mount->real_mount, flags, mount_operation, cancellable, async_wrapper_callback, data); } static gboolean g_proxy_shadow_mount_unmount_with_operation_finish (GMount *mount, GAsyncResult *result, GError **error) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); return g_mount_unmount_with_operation_finish (proxy_shadow_mount->real_mount, result, error); } static void g_proxy_shadow_mount_unmount (GMount *mount, GMountUnmountFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_proxy_shadow_mount_unmount_with_operation (mount, flags, NULL, cancellable, callback, user_data); } static gboolean g_proxy_shadow_mount_unmount_finish (GMount *mount, GAsyncResult *result, GError **error) { return g_proxy_shadow_mount_unmount_with_operation_finish (mount, result, error); } static void g_proxy_shadow_mount_eject (GMount *mount, GMountUnmountFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_proxy_shadow_mount_eject_with_operation (mount, flags, NULL, cancellable, callback, user_data); } static gboolean g_proxy_shadow_mount_eject_finish (GMount *mount, GAsyncResult *result, GError **error) { return g_proxy_shadow_mount_eject_with_operation_finish (mount, result, error); } static void g_proxy_shadow_mount_guess_content_type (GMount *mount, gboolean force_rescan, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); AsyncWrapperOp *data; data = setup_async_wrapper (mount, callback, user_data); g_mount_guess_content_type (proxy_shadow_mount->real_mount, force_rescan, cancellable, async_wrapper_callback, data); } static char ** g_proxy_shadow_mount_guess_content_type_finish (GMount *mount, GAsyncResult *result, GError **error) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); return g_mount_guess_content_type_finish (proxy_shadow_mount->real_mount, result, error); } static char ** g_proxy_shadow_mount_guess_content_type_sync (GMount *mount, gboolean force_rescan, GCancellable *cancellable, GError **error) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); return g_mount_guess_content_type_sync (proxy_shadow_mount->real_mount, force_rescan, cancellable, error); } GMount * g_proxy_shadow_mount_get_real_mount (GProxyShadowMount *mount) { return g_object_ref (mount->real_mount); } GFile * g_proxy_shadow_mount_get_activation_root (GProxyShadowMount *mount) { return g_object_ref (mount->root); } static const gchar * g_proxy_shadow_mount_get_sort_key (GMount *mount) { GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount); const gchar *ret; G_LOCK (proxy_shadow_mount); ret = g_mount_get_sort_key (proxy_shadow_mount->real_mount); G_UNLOCK (proxy_shadow_mount); return ret; } static void g_proxy_shadow_mount_mount_iface_init (GMountIface *iface) { iface->get_root = g_proxy_shadow_mount_get_root; iface->get_name = g_proxy_shadow_mount_get_name; iface->get_icon = g_proxy_shadow_mount_get_icon; iface->get_symbolic_icon = g_proxy_shadow_mount_get_symbolic_icon; iface->get_uuid = g_proxy_shadow_mount_get_uuid; iface->get_drive = g_proxy_shadow_mount_get_drive; iface->get_volume = g_proxy_shadow_mount_get_volume; iface->can_unmount = g_proxy_shadow_mount_can_unmount; iface->can_eject = g_proxy_shadow_mount_can_eject; iface->unmount = g_proxy_shadow_mount_unmount; iface->unmount_finish = g_proxy_shadow_mount_unmount_finish; iface->unmount_with_operation = g_proxy_shadow_mount_unmount_with_operation; iface->unmount_with_operation_finish = g_proxy_shadow_mount_unmount_with_operation_finish; iface->eject = g_proxy_shadow_mount_eject; iface->eject_finish = g_proxy_shadow_mount_eject_finish; iface->eject_with_operation = g_proxy_shadow_mount_eject_with_operation; iface->eject_with_operation_finish = g_proxy_shadow_mount_eject_with_operation_finish; iface->guess_content_type = g_proxy_shadow_mount_guess_content_type; iface->guess_content_type_finish = g_proxy_shadow_mount_guess_content_type_finish; iface->guess_content_type_sync = g_proxy_shadow_mount_guess_content_type_sync; iface->get_sort_key = g_proxy_shadow_mount_get_sort_key; } void g_proxy_shadow_mount_register (GIOModule *module) { g_proxy_shadow_mount_register_type (G_TYPE_MODULE (module)); } typedef struct { const char *signal_name; GObject *object; GObject *other_object; } SignalEmitIdleData; static gboolean signal_emit_in_idle_do (SignalEmitIdleData *data) { if (data->other_object != NULL) { g_signal_emit_by_name (data->object, data->signal_name, data->other_object); g_object_unref (data->other_object); } else { g_signal_emit_by_name (data->object, data->signal_name); } g_object_unref (data->object); g_free (data); return FALSE; } static void signal_emit_in_idle (gpointer object, const char *signal_name, gpointer other_object) { SignalEmitIdleData *data; data = g_new0 (SignalEmitIdleData, 1); data->signal_name = signal_name; data->object = g_object_ref (G_OBJECT (object)); data->other_object = other_object != NULL ? g_object_ref (G_OBJECT (other_object)) : NULL; g_idle_add ((GSourceFunc) signal_emit_in_idle_do, data); }