Add registration hooks for extension points. Register the gio extension
[platform/upstream/glib.git] / gio / gunixvolumemonitor.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  * 
5  * Copyright (C) 2006-2007 Red Hat, Inc.
6  *
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.
11  *
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.
16  *
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.
21  *
22  * Author: Alexander Larsson <alexl@redhat.com>
23  *         David Zeuthen <davidz@redhat.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include <glib.h>
31 #include "gunixvolumemonitor.h"
32 #include "gunixmounts.h"
33 #include "gunixmount.h"
34 #include "gunixvolume.h"
35 #include "gmountprivate.h"
36 #include "glibintl.h"
37
38 #include "gioalias.h"
39
40 struct _GUnixVolumeMonitor {
41   GNativeVolumeMonitor parent;
42
43   GUnixMountMonitor *mount_monitor;
44
45   GList *last_mountpoints;
46   GList *last_mounts;
47
48   GList *volumes;
49   GList *mounts;
50 };
51
52 static void mountpoints_changed      (GUnixMountMonitor  *mount_monitor,
53                                       gpointer            user_data);
54 static void mounts_changed           (GUnixMountMonitor  *mount_monitor,
55                                       gpointer            user_data);
56 static void update_volumes           (GUnixVolumeMonitor *monitor);
57 static void update_mounts            (GUnixVolumeMonitor *monitor);
58
59 #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
60 G_DEFINE_TYPE_WITH_CODE (GUnixVolumeMonitor, g_unix_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR,
61                          g_io_extension_point_implement (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME,
62                                                          g_define_type_id,
63                                                          "unix",
64                                                          0));
65
66 static void
67 g_unix_volume_monitor_finalize (GObject *object)
68 {
69   GUnixVolumeMonitor *monitor;
70   
71   monitor = G_UNIX_VOLUME_MONITOR (object);
72
73   g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor);
74   g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor);
75                                         
76   g_object_unref (monitor->mount_monitor);
77
78   g_list_foreach (monitor->last_mountpoints, (GFunc)g_unix_mount_point_free, NULL);
79   g_list_free (monitor->last_mountpoints);
80   g_list_foreach (monitor->last_mounts, (GFunc)g_unix_mount_free, NULL);
81   g_list_free (monitor->last_mounts);
82
83   g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL);
84   g_list_free (monitor->volumes);
85   g_list_foreach (monitor->mounts, (GFunc)g_object_unref, NULL);
86   g_list_free (monitor->mounts);
87   
88   if (G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize)
89     (*G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize) (object);
90 }
91
92 static GList *
93 get_mounts (GVolumeMonitor *volume_monitor)
94 {
95   GUnixVolumeMonitor *monitor;
96   GList *l;
97   
98   monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
99
100   l = g_list_copy (monitor->mounts);
101   g_list_foreach (l, (GFunc)g_object_ref, NULL);
102
103   return l;
104 }
105
106 static GList *
107 get_volumes (GVolumeMonitor *volume_monitor)
108 {
109   GUnixVolumeMonitor *monitor;
110   GList *l;
111   
112   monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
113
114   l = g_list_copy (monitor->volumes);
115   g_list_foreach (l, (GFunc)g_object_ref, NULL);
116
117   return l;
118 }
119
120 static GList *
121 get_connected_drives (GVolumeMonitor *volume_monitor)
122 {
123   return NULL;
124 }
125
126 static GVolume *
127 get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
128 {
129   return NULL;
130 }
131
132 static GMount *
133 get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
134 {
135   return NULL;
136 }
137
138 static gboolean
139 is_supported (void)
140 {
141   return TRUE;
142 }
143
144 static GMount *
145 get_mount_for_mount_path (const char *mount_path,
146                           GCancellable *cancellable)
147 {
148   GUnixMountEntry *mount_entry;
149   GUnixMount *mount;
150
151   mount_entry = g_unix_mount_at (mount_path, NULL);
152   
153   /* TODO: Set mountable volume? */
154   mount = _g_unix_mount_new (NULL, mount_entry, NULL);
155
156   return G_MOUNT (mount);
157 }
158
159 static void
160 g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass)
161 {
162   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
163   GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
164   GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass);
165   
166   gobject_class->finalize = g_unix_volume_monitor_finalize;
167
168   monitor_class->get_mounts = get_mounts;
169   monitor_class->get_volumes = get_volumes;
170   monitor_class->get_connected_drives = get_connected_drives;
171   monitor_class->get_volume_for_uuid = get_volume_for_uuid;
172   monitor_class->get_mount_for_uuid = get_mount_for_uuid;
173   monitor_class->is_supported = is_supported;
174
175   native_class->get_mount_for_mount_path = get_mount_for_mount_path;
176 }
177
178 static void
179 mountpoints_changed (GUnixMountMonitor *mount_monitor,
180                      gpointer           user_data)
181 {
182   GUnixVolumeMonitor *unix_monitor = user_data;
183
184   /* Update both to make sure volumes are created before mounts */
185   update_volumes (unix_monitor);
186   update_mounts (unix_monitor);
187 }
188
189 static void
190 mounts_changed (GUnixMountMonitor *mount_monitor,
191                 gpointer           user_data)
192 {
193   GUnixVolumeMonitor *unix_monitor = user_data;
194
195   /* Update both to make sure volumes are created before mounts */
196   update_volumes (unix_monitor);
197   update_mounts (unix_monitor);
198 }
199
200 static void
201 g_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor)
202 {
203
204   unix_monitor->mount_monitor = g_unix_mount_monitor_new ();
205
206   g_signal_connect (unix_monitor->mount_monitor,
207                     "mounts_changed", G_CALLBACK (mounts_changed),
208                     unix_monitor);
209   
210   g_signal_connect (unix_monitor->mount_monitor,
211                     "mountpoints_changed", G_CALLBACK (mountpoints_changed),
212                     unix_monitor);
213                     
214   update_volumes (unix_monitor);
215   update_mounts (unix_monitor);
216 }
217
218 /**
219  * g_unix_volume_monitor_new:
220  * 
221  * Returns:  a new #GVolumeMonitor.
222  **/
223 GVolumeMonitor *
224 _g_unix_volume_monitor_new (void)
225 {
226   GUnixVolumeMonitor *monitor;
227
228   monitor = g_object_new (G_TYPE_UNIX_VOLUME_MONITOR, NULL);
229   
230   return G_VOLUME_MONITOR (monitor);
231 }
232
233 static void
234 diff_sorted_lists (GList         *list1, 
235                    GList         *list2, 
236                    GCompareFunc   compare,
237                    GList        **added, 
238                    GList        **removed)
239 {
240   int order;
241   
242   *added = *removed = NULL;
243   
244   while (list1 != NULL &&
245          list2 != NULL)
246     {
247       order = (*compare) (list1->data, list2->data);
248       if (order < 0)
249         {
250           *removed = g_list_prepend (*removed, list1->data);
251           list1 = list1->next;
252         }
253       else if (order > 0)
254         {
255           *added = g_list_prepend (*added, list2->data);
256           list2 = list2->next;
257         }
258       else
259         { /* same item */
260           list1 = list1->next;
261           list2 = list2->next;
262         }
263     }
264
265   while (list1 != NULL)
266     {
267       *removed = g_list_prepend (*removed, list1->data);
268       list1 = list1->next;
269     }
270   while (list2 != NULL)
271     {
272       *added = g_list_prepend (*added, list2->data);
273       list2 = list2->next;
274     }
275 }
276
277 /**
278  * _g_unix_volume_monitor_lookup_volume_for_mount_path: 
279  * @monitor:
280  * @mount_path:
281  * 
282  * Returns:  #GUnixVolume for the given @mount_path.
283  **/
284 GUnixVolume *
285 _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor *monitor,
286                                                      const char         *mount_path)
287 {
288   GList *l;
289
290   for (l = monitor->volumes; l != NULL; l = l->next)
291     {
292       GUnixVolume *volume = l->data;
293
294       if (_g_unix_volume_has_mount_path (volume, mount_path))
295         return volume;
296     }
297   
298   return NULL;
299 }
300
301 static GUnixMount *
302 find_mount_by_mountpath (GUnixVolumeMonitor *monitor,
303                          const char *mount_path)
304 {
305   GList *l;
306
307   for (l = monitor->mounts; l != NULL; l = l->next)
308     {
309       GUnixMount *mount = l->data;
310
311       if (_g_unix_mount_has_mount_path (mount, mount_path))
312         return mount;
313     }
314   
315   return NULL;
316 }
317
318 static void
319 update_volumes (GUnixVolumeMonitor *monitor)
320 {
321   GList *new_mountpoints;
322   GList *removed, *added;
323   GList *l;
324   GUnixVolume *volume;
325   
326   new_mountpoints = g_unix_mount_points_get (NULL);
327   
328   new_mountpoints = g_list_sort (new_mountpoints, (GCompareFunc) g_unix_mount_point_compare);
329   
330   diff_sorted_lists (monitor->last_mountpoints,
331                      new_mountpoints, (GCompareFunc) g_unix_mount_point_compare,
332                      &added, &removed);
333   
334   for (l = removed; l != NULL; l = l->next)
335     {
336       GUnixMountPoint *mountpoint = l->data;
337       
338       volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor,
339                                                                     g_unix_mount_point_get_mount_path (mountpoint));
340       if (volume)
341         {
342           _g_unix_volume_disconnected (volume);
343           monitor->volumes = g_list_remove (monitor->volumes, volume);
344           g_signal_emit_by_name (monitor, "volume_removed", volume);
345           g_signal_emit_by_name (volume, "removed");
346           g_object_unref (volume);
347         }
348     }
349   
350   for (l = added; l != NULL; l = l->next)
351     {
352       GUnixMountPoint *mountpoint = l->data;
353       
354       volume = _g_unix_volume_new (G_VOLUME_MONITOR (monitor), mountpoint);
355       if (volume)
356         {
357           monitor->volumes = g_list_prepend (monitor->volumes, volume);
358           g_signal_emit_by_name (monitor, "volume_added", volume);
359         }
360     }
361   
362   g_list_free (added);
363   g_list_free (removed);
364   g_list_foreach (monitor->last_mountpoints,
365                   (GFunc)g_unix_mount_point_free, NULL);
366   g_list_free (monitor->last_mountpoints);
367   monitor->last_mountpoints = new_mountpoints;
368 }
369
370 static void
371 update_mounts (GUnixVolumeMonitor *monitor)
372 {
373   GList *new_mounts;
374   GList *removed, *added;
375   GList *l;
376   GUnixMount *mount;
377   GUnixVolume *volume;
378   const char *mount_path;
379   
380   new_mounts = g_unix_mounts_get (NULL);
381   
382   new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
383   
384   diff_sorted_lists (monitor->last_mounts,
385                      new_mounts, (GCompareFunc) g_unix_mount_compare,
386                      &added, &removed);
387   
388   for (l = removed; l != NULL; l = l->next)
389     {
390       GUnixMountEntry *mount_entry = l->data;
391       
392       mount = find_mount_by_mountpath (monitor, g_unix_mount_get_mount_path (mount_entry));
393       if (mount)
394         {
395           _g_unix_mount_unmounted (mount);
396           monitor->mounts = g_list_remove (monitor->mounts, mount);
397           g_signal_emit_by_name (monitor, "mount_removed", mount);
398           g_signal_emit_by_name (mount, "unmounted");
399           g_object_unref (mount);
400         }
401     }
402   
403   for (l = added; l != NULL; l = l->next)
404     {
405       GUnixMountEntry *mount_entry = l->data;
406
407       mount_path = g_unix_mount_get_mount_path (mount_entry);
408       
409       volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor, mount_path);
410       mount = _g_unix_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume);
411       if (mount)
412         {
413           monitor->mounts = g_list_prepend (monitor->mounts, mount);
414           g_signal_emit_by_name (monitor, "mount_added", mount);
415         }
416     }
417   
418   g_list_free (added);
419   g_list_free (removed);
420   g_list_foreach (monitor->last_mounts,
421                   (GFunc)g_unix_mount_free, NULL);
422   g_list_free (monitor->last_mounts);
423   monitor->last_mounts = new_mounts;
424 }