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.1 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 _g_unix_volume_monitor_update (GUnixVolumeMonitor
*unix_monitor
)
189 /* Update both to make sure volumes are created before mounts */
190 update_volumes (unix_monitor
);
191 update_mounts (unix_monitor
);
195 mountpoints_changed (GUnixMountMonitor
*mount_monitor
,
198 GUnixVolumeMonitor
*unix_monitor
= user_data
;
200 _g_unix_volume_monitor_update (unix_monitor
);
204 mounts_changed (GUnixMountMonitor
*mount_monitor
,
207 GUnixVolumeMonitor
*unix_monitor
= user_data
;
209 _g_unix_volume_monitor_update (unix_monitor
);
213 g_unix_volume_monitor_init (GUnixVolumeMonitor
*unix_monitor
)
216 unix_monitor
->mount_monitor
= g_unix_mount_monitor_get ();
218 g_signal_connect (unix_monitor
->mount_monitor
,
219 "mounts-changed", G_CALLBACK (mounts_changed
),
222 g_signal_connect (unix_monitor
->mount_monitor
,
223 "mountpoints-changed", G_CALLBACK (mountpoints_changed
),
226 _g_unix_volume_monitor_update (unix_monitor
);
230 _g_unix_volume_monitor_new (void)
232 GUnixVolumeMonitor
*monitor
;
234 monitor
= g_object_new (G_TYPE_UNIX_VOLUME_MONITOR
, NULL
);
236 return G_VOLUME_MONITOR (monitor
);
240 diff_sorted_lists (GList
*list1
,
242 GCompareFunc compare
,
248 *added
= *removed
= NULL
;
250 while (list1
!= NULL
&&
253 order
= (*compare
) (list1
->data
, list2
->data
);
256 *removed
= g_list_prepend (*removed
, list1
->data
);
261 *added
= g_list_prepend (*added
, list2
->data
);
271 while (list1
!= NULL
)
273 *removed
= g_list_prepend (*removed
, list1
->data
);
276 while (list2
!= NULL
)
278 *added
= g_list_prepend (*added
, list2
->data
);
284 _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor
*monitor
,
285 const char *mount_path
)
289 for (l
= monitor
->volumes
; l
!= NULL
; l
= l
->next
)
291 GUnixVolume
*volume
= l
->data
;
293 if (_g_unix_volume_has_mount_path (volume
, mount_path
))
301 find_mount_by_mountpath (GUnixVolumeMonitor
*monitor
,
302 const char *mount_path
)
306 for (l
= monitor
->mounts
; l
!= NULL
; l
= l
->next
)
308 GUnixMount
*mount
= l
->data
;
310 if (_g_unix_mount_has_mount_path (mount
, mount_path
))
318 update_volumes (GUnixVolumeMonitor
*monitor
)
320 GList
*new_mountpoints
;
321 GList
*removed
, *added
;
325 new_mountpoints
= g_unix_mount_points_get (NULL
);
327 new_mountpoints
= g_list_sort (new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
);
329 diff_sorted_lists (monitor
->last_mountpoints
,
330 new_mountpoints
, (GCompareFunc
) g_unix_mount_point_compare
,
333 for (l
= removed
; l
!= NULL
; l
= l
->next
)
335 GUnixMountPoint
*mountpoint
= l
->data
;
337 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
,
338 g_unix_mount_point_get_mount_path (mountpoint
));
341 _g_unix_volume_disconnected (volume
);
342 monitor
->volumes
= g_list_remove (monitor
->volumes
, volume
);
343 g_signal_emit_by_name (monitor
, "volume-removed", volume
);
344 g_signal_emit_by_name (volume
, "removed");
345 g_object_unref (volume
);
349 for (l
= added
; l
!= NULL
; l
= l
->next
)
351 GUnixMountPoint
*mountpoint
= l
->data
;
353 volume
= _g_unix_volume_new (G_VOLUME_MONITOR (monitor
), mountpoint
);
356 monitor
->volumes
= g_list_prepend (monitor
->volumes
, volume
);
357 g_signal_emit_by_name (monitor
, "volume-added", volume
);
362 g_list_free (removed
);
363 g_list_free_full (monitor
->last_mountpoints
, (GDestroyNotify
) g_unix_mount_point_free
);
364 monitor
->last_mountpoints
= new_mountpoints
;
368 update_mounts (GUnixVolumeMonitor
*monitor
)
371 GList
*removed
, *added
;
375 const char *mount_path
;
377 new_mounts
= g_unix_mounts_get (NULL
);
379 new_mounts
= g_list_sort (new_mounts
, (GCompareFunc
) g_unix_mount_compare
);
381 diff_sorted_lists (monitor
->last_mounts
,
382 new_mounts
, (GCompareFunc
) g_unix_mount_compare
,
385 for (l
= removed
; l
!= NULL
; l
= l
->next
)
387 GUnixMountEntry
*mount_entry
= l
->data
;
389 mount
= find_mount_by_mountpath (monitor
, g_unix_mount_get_mount_path (mount_entry
));
392 _g_unix_mount_unmounted (mount
);
393 monitor
->mounts
= g_list_remove (monitor
->mounts
, mount
);
394 g_signal_emit_by_name (monitor
, "mount-removed", mount
);
395 g_signal_emit_by_name (mount
, "unmounted");
396 g_object_unref (mount
);
400 for (l
= added
; l
!= NULL
; l
= l
->next
)
402 GUnixMountEntry
*mount_entry
= l
->data
;
404 mount_path
= g_unix_mount_get_mount_path (mount_entry
);
406 volume
= _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor
, mount_path
);
407 mount
= _g_unix_mount_new (G_VOLUME_MONITOR (monitor
), mount_entry
, volume
);
410 monitor
->mounts
= g_list_prepend (monitor
->mounts
, mount
);
411 g_signal_emit_by_name (monitor
, "mount-added", mount
);
416 g_list_free (removed
);
417 g_list_free_full (monitor
->last_mounts
, (GDestroyNotify
) g_unix_mount_free
);
418 monitor
->last_mounts
= new_mounts
;