1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2006-2007 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 * Author: Alexander Larsson <alexl@redhat.com>
21 * David Zeuthen <davidz@redhat.com>
29 #include "gunixvolumemonitor.h"
30 #include "gunixmounts.h"
31 #include "gunixmount.h"
32 #include "gunixvolume.h"
34 #include "gmountprivate.h"
35 #include "giomodule.h"
39 struct _GUnixVolumeMonitor
{
40 GNativeVolumeMonitor parent
;
42 GUnixMountMonitor
*mount_monitor
;
44 GList
*last_mountpoints
;
51 static void mountpoints_changed (GUnixMountMonitor
*mount_monitor
,
53 static void mounts_changed (GUnixMountMonitor
*mount_monitor
,
55 static void update_volumes (GUnixVolumeMonitor
*monitor
);
56 static void update_mounts (GUnixVolumeMonitor
*monitor
);
58 #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
59 G_DEFINE_TYPE_WITH_CODE (GUnixVolumeMonitor
, g_unix_volume_monitor
, G_TYPE_NATIVE_VOLUME_MONITOR
,
60 g_io_extension_point_implement (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME
,
66 g_unix_volume_monitor_finalize (GObject
*object
)
68 GUnixVolumeMonitor
*monitor
;
70 monitor
= G_UNIX_VOLUME_MONITOR (object
);
72 g_signal_handlers_disconnect_by_func (monitor
->mount_monitor
, mountpoints_changed
, monitor
);
73 g_signal_handlers_disconnect_by_func (monitor
->mount_monitor
, mounts_changed
, monitor
);
75 g_object_unref (monitor
->mount_monitor
);
77 g_list_free_full (monitor
->last_mountpoints
, (GDestroyNotify
) g_unix_mount_point_free
);
78 g_list_free_full (monitor
->last_mounts
, (GDestroyNotify
) g_unix_mount_free
);
80 g_list_free_full (monitor
->volumes
, g_object_unref
);
81 g_list_free_full (monitor
->mounts
, g_object_unref
);
83 G_OBJECT_CLASS (g_unix_volume_monitor_parent_class
)->finalize (object
);
87 g_unix_volume_monitor_dispose (GObject
*object
)
89 GUnixVolumeMonitor
*monitor
;
91 monitor
= G_UNIX_VOLUME_MONITOR (object
);
93 g_list_free_full (monitor
->volumes
, g_object_unref
);
94 monitor
->volumes
= NULL
;
96 g_list_free_full (monitor
->mounts
, g_object_unref
);
97 monitor
->mounts
= NULL
;
99 G_OBJECT_CLASS (g_unix_volume_monitor_parent_class
)->dispose (object
);
103 get_mounts (GVolumeMonitor
*volume_monitor
)
105 GUnixVolumeMonitor
*monitor
;
107 monitor
= G_UNIX_VOLUME_MONITOR (volume_monitor
);
109 return g_list_copy_deep (monitor
->mounts
, (GCopyFunc
) g_object_ref
, NULL
);
113 get_volumes (GVolumeMonitor
*volume_monitor
)
115 GUnixVolumeMonitor
*monitor
;
117 monitor
= G_UNIX_VOLUME_MONITOR (volume_monitor
);
119 return g_list_copy_deep (monitor
->volumes
, (GCopyFunc
) g_object_ref
, NULL
);
123 get_connected_drives (GVolumeMonitor
*volume_monitor
)
129 get_volume_for_uuid (GVolumeMonitor
*volume_monitor
, const char *uuid
)
135 get_mount_for_uuid (GVolumeMonitor
*volume_monitor
, const char *uuid
)
147 get_mount_for_mount_path (const char *mount_path
,
148 GCancellable
*cancellable
)
150 GUnixMountEntry
*mount_entry
;
153 mount_entry
= g_unix_mount_at (mount_path
, NULL
);
158 /* TODO: Set mountable volume? */
159 mount
= _g_unix_mount_new (NULL
, mount_entry
, NULL
);
161 g_unix_mount_free (mount_entry
);
163 return G_MOUNT (mount
);
167 g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass
*klass
)
169 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
170 GVolumeMonitorClass
*monitor_class
= G_VOLUME_MONITOR_CLASS (klass
);
171 GNativeVolumeMonitorClass
*native_class
= G_NATIVE_VOLUME_MONITOR_CLASS (klass
);
173 gobject_class
->finalize
= g_unix_volume_monitor_finalize
;
174 gobject_class
->dispose
= g_unix_volume_monitor_dispose
;
176 monitor_class
->get_mounts
= get_mounts
;
177 monitor_class
->get_volumes
= get_volumes
;
178 monitor_class
->get_connected_drives
= get_connected_drives
;
179 monitor_class
->get_volume_for_uuid
= get_volume_for_uuid
;
180 monitor_class
->get_mount_for_uuid
= get_mount_for_uuid
;
181 monitor_class
->is_supported
= is_supported
;
183 native_class
->get_mount_for_mount_path
= get_mount_for_mount_path
;
187 mountpoints_changed (GUnixMountMonitor
*mount_monitor
,
190 GUnixVolumeMonitor
*unix_monitor
= user_data
;
192 /* Update both to make sure volumes are created before mounts */
193 update_volumes (unix_monitor
);
194 update_mounts (unix_monitor
);
198 mounts_changed (GUnixMountMonitor
*mount_monitor
,
201 GUnixVolumeMonitor
*unix_monitor
= user_data
;
203 /* Update both to make sure volumes are created before mounts */
204 update_volumes (unix_monitor
);
205 update_mounts (unix_monitor
);
209 g_unix_volume_monitor_init (GUnixVolumeMonitor
*unix_monitor
)
212 unix_monitor
->mount_monitor
= g_unix_mount_monitor_get ();
214 g_signal_connect (unix_monitor
->mount_monitor
,
215 "mounts-changed", G_CALLBACK (mounts_changed
),
218 g_signal_connect (unix_monitor
->mount_monitor
,
219 "mountpoints-changed", G_CALLBACK (mountpoints_changed
),
222 update_volumes (unix_monitor
);
223 update_mounts (unix_monitor
);
227 _g_unix_volume_monitor_new (void)
229 GUnixVolumeMonitor
*monitor
;
231 monitor
= g_object_new (G_TYPE_UNIX_VOLUME_MONITOR
, NULL
);
233 return G_VOLUME_MONITOR (monitor
);
237 diff_sorted_lists (GList
*list1
,
239 GCompareFunc compare
,
245 *added
= *removed
= NULL
;
247 while (list1
!= NULL
&&
250 order
= (*compare
) (list1
->data
, list2
->data
);
253 *removed
= g_list_prepend (*removed
, list1
->data
);
258 *added
= g_list_prepend (*added
, list2
->data
);
268 while (list1
!= NULL
)
270 *removed
= g_list_prepend (*removed
, list1
->data
);
273 while (list2
!= NULL
)
275 *added
= g_list_prepend (*added
, list2
->data
);
281 _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor
*monitor
,
282 const char *mount_path
)
286 for (l
= monitor
->volumes
; l
!= NULL
; l
= l
->next
)
288 GUnixVolume
*volume
= l
->data
;
290 if (_g_unix_volume_has_mount_path (volume
, mount_path
))
298 find_mount_by_mountpath (GUnixVolumeMonitor
*monitor
,
299 const char *mount_path
)
303 for (l
= monitor
->mounts
; l
!= NULL
; l
= l
->next
)
305 GUnixMount
*mount
= l
->data
;
307 if (_g_unix_mount_has_mount_path (mount
, mount_path
))
315 update_volumes (GUnixVolumeMonitor
*monitor
)
317 GList
*new_mountpoints
;
318 GList
*removed
, *added
;
322 new_mountpoints
= g_unix_mount_points_get (NULL
);
324 new_mountpoints
= g_list_sort (new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
);
326 diff_sorted_lists (monitor
->last_mountpoints
,
327 new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
,
330 for (l
= removed
; l
!= NULL
; l
= l
->next
)
332 GUnixMountPoint
*mountpoint
= l
->data
;
334 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
,
335 g_unix_mount_point_get_mount_path (mountpoint
));
338 _g_unix_volume_disconnected (volume
);
339 monitor
->volumes
= g_list_remove (monitor
->volumes
, volume
);
340 g_signal_emit_by_name (monitor
, "volume-removed", volume
);
341 g_signal_emit_by_name (volume
, "removed");
342 g_object_unref (volume
);
346 for (l
= added
; l
!= NULL
; l
= l
->next
)
348 GUnixMountPoint
*mountpoint
= l
->data
;
350 volume
= _g_unix_volume_new (G_VOLUME_MONITOR (monitor
), mountpoint
);
353 monitor
->volumes
= g_list_prepend (monitor
->volumes
, volume
);
354 g_signal_emit_by_name (monitor
, "volume-added", volume
);
359 g_list_free (removed
);
360 g_list_free_full (monitor
->last_mountpoints
, (GDestroyNotify
) g_unix_mount_point_free
);
361 monitor
->last_mountpoints
= new_mountpoints
;
365 update_mounts (GUnixVolumeMonitor
*monitor
)
368 GList
*removed
, *added
;
372 const char *mount_path
;
374 new_mounts
= g_unix_mounts_get (NULL
);
376 new_mounts
= g_list_sort (new_mounts
, (GCompareFunc
) g_unix_mount_compare
);
378 diff_sorted_lists (monitor
->last_mounts
,
379 new_mounts
, (GCompareFunc
) g_unix_mount_compare
,
382 for (l
= removed
; l
!= NULL
; l
= l
->next
)
384 GUnixMountEntry
*mount_entry
= l
->data
;
386 mount
= find_mount_by_mountpath (monitor
, g_unix_mount_get_mount_path (mount_entry
));
389 _g_unix_mount_unmounted (mount
);
390 monitor
->mounts
= g_list_remove (monitor
->mounts
, mount
);
391 g_signal_emit_by_name (monitor
, "mount-removed", mount
);
392 g_signal_emit_by_name (mount
, "unmounted");
393 g_object_unref (mount
);
397 for (l
= added
; l
!= NULL
; l
= l
->next
)
399 GUnixMountEntry
*mount_entry
= l
->data
;
401 mount_path
= g_unix_mount_get_mount_path (mount_entry
);
403 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
, mount_path
);
404 mount
= _g_unix_mount_new (G_VOLUME_MONITOR (monitor
), mount_entry
, volume
);
407 monitor
->mounts
= g_list_prepend (monitor
->mounts
, mount
);
408 g_signal_emit_by_name (monitor
, "mount-added", mount
);
413 g_list_free (removed
);
414 g_list_free_full (monitor
->last_mounts
, (GDestroyNotify
) g_unix_mount_free
);
415 monitor
->last_mounts
= new_mounts
;