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, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Author: Alexander Larsson <alexl@redhat.com>
23 * David Zeuthen <davidz@redhat.com>
31 #include "gunixvolumemonitor.h"
32 #include "gunixmounts.h"
33 #include "gunixmount.h"
34 #include "gunixvolume.h"
36 #include "gmountprivate.h"
37 #include "giomodule.h"
41 struct _GUnixVolumeMonitor
{
42 GNativeVolumeMonitor parent
;
44 GUnixMountMonitor
*mount_monitor
;
46 GList
*last_mountpoints
;
53 static void mountpoints_changed (GUnixMountMonitor
*mount_monitor
,
55 static void mounts_changed (GUnixMountMonitor
*mount_monitor
,
57 static void update_volumes (GUnixVolumeMonitor
*monitor
);
58 static void update_mounts (GUnixVolumeMonitor
*monitor
);
60 #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
61 G_DEFINE_TYPE_WITH_CODE (GUnixVolumeMonitor
, g_unix_volume_monitor
, G_TYPE_NATIVE_VOLUME_MONITOR
,
62 g_io_extension_point_implement (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME
,
68 g_unix_volume_monitor_finalize (GObject
*object
)
70 GUnixVolumeMonitor
*monitor
;
72 monitor
= G_UNIX_VOLUME_MONITOR (object
);
74 g_signal_handlers_disconnect_by_func (monitor
->mount_monitor
, mountpoints_changed
, monitor
);
75 g_signal_handlers_disconnect_by_func (monitor
->mount_monitor
, mounts_changed
, monitor
);
77 g_object_unref (monitor
->mount_monitor
);
79 g_list_free_full (monitor
->last_mountpoints
, (GDestroyNotify
) g_unix_mount_point_free
);
80 g_list_free_full (monitor
->last_mounts
, (GDestroyNotify
) g_unix_mount_free
);
82 g_list_free_full (monitor
->volumes
, g_object_unref
);
83 g_list_free_full (monitor
->mounts
, g_object_unref
);
85 G_OBJECT_CLASS (g_unix_volume_monitor_parent_class
)->finalize (object
);
89 g_unix_volume_monitor_dispose (GObject
*object
)
91 GUnixVolumeMonitor
*monitor
;
93 monitor
= G_UNIX_VOLUME_MONITOR (object
);
95 g_list_free_full (monitor
->volumes
, g_object_unref
);
96 monitor
->volumes
= NULL
;
98 g_list_free_full (monitor
->mounts
, g_object_unref
);
99 monitor
->mounts
= NULL
;
101 G_OBJECT_CLASS (g_unix_volume_monitor_parent_class
)->dispose (object
);
105 get_mounts (GVolumeMonitor
*volume_monitor
)
107 GUnixVolumeMonitor
*monitor
;
109 monitor
= G_UNIX_VOLUME_MONITOR (volume_monitor
);
111 return g_list_copy_deep (monitor
->mounts
, (GCopyFunc
) g_object_ref
, NULL
);
115 get_volumes (GVolumeMonitor
*volume_monitor
)
117 GUnixVolumeMonitor
*monitor
;
119 monitor
= G_UNIX_VOLUME_MONITOR (volume_monitor
);
121 return g_list_copy_deep (monitor
->volumes
, (GCopyFunc
) g_object_ref
, NULL
);
125 get_connected_drives (GVolumeMonitor
*volume_monitor
)
131 get_volume_for_uuid (GVolumeMonitor
*volume_monitor
, const char *uuid
)
137 get_mount_for_uuid (GVolumeMonitor
*volume_monitor
, const char *uuid
)
149 get_mount_for_mount_path (const char *mount_path
,
150 GCancellable
*cancellable
)
152 GUnixMountEntry
*mount_entry
;
155 mount_entry
= g_unix_mount_at (mount_path
, NULL
);
160 /* TODO: Set mountable volume? */
161 mount
= _g_unix_mount_new (NULL
, mount_entry
, NULL
);
163 g_unix_mount_free (mount_entry
);
165 return G_MOUNT (mount
);
169 g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass
*klass
)
171 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
172 GVolumeMonitorClass
*monitor_class
= G_VOLUME_MONITOR_CLASS (klass
);
173 GNativeVolumeMonitorClass
*native_class
= G_NATIVE_VOLUME_MONITOR_CLASS (klass
);
175 gobject_class
->finalize
= g_unix_volume_monitor_finalize
;
176 gobject_class
->dispose
= g_unix_volume_monitor_dispose
;
178 monitor_class
->get_mounts
= get_mounts
;
179 monitor_class
->get_volumes
= get_volumes
;
180 monitor_class
->get_connected_drives
= get_connected_drives
;
181 monitor_class
->get_volume_for_uuid
= get_volume_for_uuid
;
182 monitor_class
->get_mount_for_uuid
= get_mount_for_uuid
;
183 monitor_class
->is_supported
= is_supported
;
185 native_class
->get_mount_for_mount_path
= get_mount_for_mount_path
;
189 mountpoints_changed (GUnixMountMonitor
*mount_monitor
,
192 GUnixVolumeMonitor
*unix_monitor
= user_data
;
194 /* Update both to make sure volumes are created before mounts */
195 update_volumes (unix_monitor
);
196 update_mounts (unix_monitor
);
200 mounts_changed (GUnixMountMonitor
*mount_monitor
,
203 GUnixVolumeMonitor
*unix_monitor
= user_data
;
205 /* Update both to make sure volumes are created before mounts */
206 update_volumes (unix_monitor
);
207 update_mounts (unix_monitor
);
211 g_unix_volume_monitor_init (GUnixVolumeMonitor
*unix_monitor
)
214 unix_monitor
->mount_monitor
= g_unix_mount_monitor_new ();
216 g_signal_connect (unix_monitor
->mount_monitor
,
217 "mounts-changed", G_CALLBACK (mounts_changed
),
220 g_signal_connect (unix_monitor
->mount_monitor
,
221 "mountpoints-changed", G_CALLBACK (mountpoints_changed
),
224 update_volumes (unix_monitor
);
225 update_mounts (unix_monitor
);
229 _g_unix_volume_monitor_new (void)
231 GUnixVolumeMonitor
*monitor
;
233 monitor
= g_object_new (G_TYPE_UNIX_VOLUME_MONITOR
, NULL
);
235 return G_VOLUME_MONITOR (monitor
);
239 diff_sorted_lists (GList
*list1
,
241 GCompareFunc compare
,
247 *added
= *removed
= NULL
;
249 while (list1
!= NULL
&&
252 order
= (*compare
) (list1
->data
, list2
->data
);
255 *removed
= g_list_prepend (*removed
, list1
->data
);
260 *added
= g_list_prepend (*added
, list2
->data
);
270 while (list1
!= NULL
)
272 *removed
= g_list_prepend (*removed
, list1
->data
);
275 while (list2
!= NULL
)
277 *added
= g_list_prepend (*added
, list2
->data
);
283 _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor
*monitor
,
284 const char *mount_path
)
288 for (l
= monitor
->volumes
; l
!= NULL
; l
= l
->next
)
290 GUnixVolume
*volume
= l
->data
;
292 if (_g_unix_volume_has_mount_path (volume
, mount_path
))
300 find_mount_by_mountpath (GUnixVolumeMonitor
*monitor
,
301 const char *mount_path
)
305 for (l
= monitor
->mounts
; l
!= NULL
; l
= l
->next
)
307 GUnixMount
*mount
= l
->data
;
309 if (_g_unix_mount_has_mount_path (mount
, mount_path
))
317 update_volumes (GUnixVolumeMonitor
*monitor
)
319 GList
*new_mountpoints
;
320 GList
*removed
, *added
;
324 new_mountpoints
= g_unix_mount_points_get (NULL
);
326 new_mountpoints
= g_list_sort (new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
);
328 diff_sorted_lists (monitor
->last_mountpoints
,
329 new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
,
332 for (l
= removed
; l
!= NULL
; l
= l
->next
)
334 GUnixMountPoint
*mountpoint
= l
->data
;
336 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
,
337 g_unix_mount_point_get_mount_path (mountpoint
));
340 _g_unix_volume_disconnected (volume
);
341 monitor
->volumes
= g_list_remove (monitor
->volumes
, volume
);
342 g_signal_emit_by_name (monitor
, "volume-removed", volume
);
343 g_signal_emit_by_name (volume
, "removed");
344 g_object_unref (volume
);
348 for (l
= added
; l
!= NULL
; l
= l
->next
)
350 GUnixMountPoint
*mountpoint
= l
->data
;
352 volume
= _g_unix_volume_new (G_VOLUME_MONITOR (monitor
), mountpoint
);
355 monitor
->volumes
= g_list_prepend (monitor
->volumes
, volume
);
356 g_signal_emit_by_name (monitor
, "volume-added", volume
);
361 g_list_free (removed
);
362 g_list_free_full (monitor
->last_mountpoints
, (GDestroyNotify
) g_unix_mount_point_free
);
363 monitor
->last_mountpoints
= new_mountpoints
;
367 update_mounts (GUnixVolumeMonitor
*monitor
)
370 GList
*removed
, *added
;
374 const char *mount_path
;
376 new_mounts
= g_unix_mounts_get (NULL
);
378 new_mounts
= g_list_sort (new_mounts
, (GCompareFunc
) g_unix_mount_compare
);
380 diff_sorted_lists (monitor
->last_mounts
,
381 new_mounts
, (GCompareFunc
) g_unix_mount_compare
,
384 for (l
= removed
; l
!= NULL
; l
= l
->next
)
386 GUnixMountEntry
*mount_entry
= l
->data
;
388 mount
= find_mount_by_mountpath (monitor
, g_unix_mount_get_mount_path (mount_entry
));
391 _g_unix_mount_unmounted (mount
);
392 monitor
->mounts
= g_list_remove (monitor
->mounts
, mount
);
393 g_signal_emit_by_name (monitor
, "mount-removed", mount
);
394 g_signal_emit_by_name (mount
, "unmounted");
395 g_object_unref (mount
);
399 for (l
= added
; l
!= NULL
; l
= l
->next
)
401 GUnixMountEntry
*mount_entry
= l
->data
;
403 mount_path
= g_unix_mount_get_mount_path (mount_entry
);
405 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
, mount_path
);
406 mount
= _g_unix_mount_new (G_VOLUME_MONITOR (monitor
), mount_entry
, volume
);
409 monitor
->mounts
= g_list_prepend (monitor
->mounts
, mount
);
410 g_signal_emit_by_name (monitor
, "mount-added", mount
);
415 g_list_free (removed
);
416 g_list_free_full (monitor
->last_mounts
, (GDestroyNotify
) g_unix_mount_free
);
417 monitor
->last_mounts
= new_mounts
;