Removed unnecessary file
[platform/upstream/glib.git] / gio / gunixvolumemonitor.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include <glib.h>
28 #include "gunixvolumemonitor.h"
29 #include "gunixmounts.h"
30 #include "gunixvolume.h"
31 #include "gunixdrive.h"
32 #include "gvolumeprivate.h"
33 #include "glibintl.h"
34
35 #include "gioalias.h"
36
37 struct _GUnixVolumeMonitor {
38   GNativeVolumeMonitor parent;
39
40   GUnixMountMonitor *mount_monitor;
41
42   GList *last_mountpoints;
43   GList *last_mounts;
44
45   GList *drives;
46   GList *volumes;
47 };
48
49 static void mountpoints_changed (GUnixMountMonitor  *mount_monitor,
50                                  gpointer            user_data);
51 static void mounts_changed      (GUnixMountMonitor  *mount_monitor,
52                                  gpointer            user_data);
53 static void update_drives       (GUnixVolumeMonitor *monitor);
54 static void update_volumes      (GUnixVolumeMonitor *monitor);
55
56 #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
57 G_DEFINE_TYPE (GUnixVolumeMonitor, g_unix_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR);
58
59 static void
60 g_unix_volume_monitor_finalize (GObject *object)
61 {
62   GUnixVolumeMonitor *monitor;
63   
64   monitor = G_UNIX_VOLUME_MONITOR (object);
65
66   g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor);
67   g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor);
68                                         
69   g_object_unref (monitor->mount_monitor);
70
71   g_list_foreach (monitor->last_mounts, (GFunc)g_unix_mount_free, NULL);
72   g_list_free (monitor->last_mounts);
73
74   g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL);
75   g_list_free (monitor->volumes);
76   g_list_foreach (monitor->drives, (GFunc)g_object_unref, NULL);
77   g_list_free (monitor->drives);
78   
79   if (G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize)
80     (*G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize) (object);
81 }
82
83 static GList *
84 get_mounted_volumes (GVolumeMonitor *volume_monitor)
85 {
86   GUnixVolumeMonitor *monitor;
87   GList *l;
88   
89   monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
90
91   l = g_list_copy (monitor->volumes);
92   g_list_foreach (l, (GFunc)g_object_ref, NULL);
93
94   return l;
95 }
96
97 static GList *
98 get_connected_drives (GVolumeMonitor *volume_monitor)
99 {
100   GUnixVolumeMonitor *monitor;
101   GList *l;
102   
103   monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
104
105   l = g_list_copy (monitor->drives);
106   g_list_foreach (l, (GFunc)g_object_ref, NULL);
107
108   return l;
109 }
110
111 static GVolume *
112 get_volume_for_mountpoint (const char *mountpoint)
113 {
114   GUnixMount *mount;
115   GUnixVolume *volume;
116
117   mount = g_get_unix_mount_at (mountpoint, NULL);
118   
119   /* TODO: Set drive? */
120   volume = _g_unix_volume_new (mount, NULL);
121
122   return G_VOLUME (volume);
123 }
124
125 static void
126 g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129   GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
130   GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass);
131   
132   gobject_class->finalize = g_unix_volume_monitor_finalize;
133
134   monitor_class->get_mounted_volumes = get_mounted_volumes;
135   monitor_class->get_connected_drives = get_connected_drives;
136
137   native_class->priority = 0;
138   native_class->get_volume_for_mountpoint = get_volume_for_mountpoint;
139 }
140
141 static void
142 mountpoints_changed (GUnixMountMonitor *mount_monitor,
143                      gpointer user_data)
144 {
145   GUnixVolumeMonitor *unix_monitor = user_data;
146
147   /* Update both to make sure drives are created before volumes */
148   update_drives (unix_monitor);
149   update_volumes (unix_monitor);
150 }
151
152 static void
153 mounts_changed (GUnixMountMonitor *mount_monitor,
154                 gpointer user_data)
155 {
156   GUnixVolumeMonitor *unix_monitor = user_data;
157
158   /* Update both to make sure drives are created before volumes */
159   update_drives (unix_monitor);
160   update_volumes (unix_monitor);
161 }
162
163 static void
164 g_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor)
165 {
166
167   unix_monitor->mount_monitor = g_unix_mount_monitor_new ();
168
169   g_signal_connect (unix_monitor->mount_monitor,
170                     "mounts_changed", G_CALLBACK (mounts_changed),
171                     unix_monitor);
172   
173   g_signal_connect (unix_monitor->mount_monitor,
174                     "mountpoints_changed", G_CALLBACK (mountpoints_changed),
175                     unix_monitor);
176                     
177   update_drives (unix_monitor);
178   update_volumes (unix_monitor);
179
180 }
181
182 /**
183  * g_unix_volume_monitor_new:
184  * 
185  * Returns:  a new #GVolumeMonitor.
186  **/
187 GVolumeMonitor *
188 _g_unix_volume_monitor_new (void)
189 {
190   GUnixVolumeMonitor *monitor;
191
192   monitor = g_object_new (G_TYPE_UNIX_VOLUME_MONITOR, NULL);
193   
194   return G_VOLUME_MONITOR (monitor);
195 }
196
197 static void
198 diff_sorted_lists (GList *list1, GList *list2, GCompareFunc compare,
199                    GList **added, GList **removed)
200 {
201   int order;
202   
203   *added = *removed = NULL;
204   
205   while (list1 != NULL &&
206          list2 != NULL)
207     {
208       order = (*compare) (list1->data, list2->data);
209       if (order < 0)
210         {
211           *removed = g_list_prepend (*removed, list1->data);
212           list1 = list1->next;
213         }
214       else if (order > 0)
215         {
216           *added = g_list_prepend (*added, list2->data);
217           list2 = list2->next;
218         }
219       else
220         { /* same item */
221           list1 = list1->next;
222           list2 = list2->next;
223         }
224     }
225
226   while (list1 != NULL)
227     {
228       *removed = g_list_prepend (*removed, list1->data);
229       list1 = list1->next;
230     }
231   while (list2 != NULL)
232     {
233       *added = g_list_prepend (*added, list2->data);
234       list2 = list2->next;
235     }
236 }
237
238 /**
239  * g_unix_volume_lookup_drive_for_mountpoint: 
240  * @monitor:
241  * @mountpoint:
242  * 
243  * Returns:  #GUnixDrive for the given @mountpoint.
244  **/
245 GUnixDrive *
246 _g_unix_volume_monitor_lookup_drive_for_mountpoint (GUnixVolumeMonitor *monitor,
247                                                     const char *mountpoint)
248 {
249   GList *l;
250
251   for (l = monitor->drives; l != NULL; l = l->next)
252     {
253       GUnixDrive *drive = l->data;
254
255       if (_g_unix_drive_has_mountpoint (drive, mountpoint))
256         return drive;
257     }
258   
259   return NULL;
260 }
261
262 static GUnixVolume *
263 find_volume_by_mountpoint (GUnixVolumeMonitor *monitor,
264                            const char *mountpoint)
265 {
266   GList *l;
267
268   for (l = monitor->volumes; l != NULL; l = l->next)
269     {
270       GUnixVolume *volume = l->data;
271
272       if (_g_unix_volume_has_mountpoint (volume, mountpoint))
273         return volume;
274     }
275   
276   return NULL;
277 }
278
279 static void
280 update_drives (GUnixVolumeMonitor *monitor)
281 {
282   GList *new_mountpoints;
283   GList *removed, *added;
284   GList *l;
285   GUnixDrive *drive;
286   
287   new_mountpoints = g_get_unix_mount_points (NULL);
288   
289   new_mountpoints = g_list_sort (new_mountpoints, (GCompareFunc) g_unix_mount_point_compare);
290   
291   diff_sorted_lists (monitor->last_mountpoints,
292                      new_mountpoints, (GCompareFunc) g_unix_mount_point_compare,
293                      &added, &removed);
294   
295   for (l = removed; l != NULL; l = l->next)
296     {
297       GUnixMountPoint *mountpoint = l->data;
298       
299       drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor,
300                                                                   g_unix_mount_point_get_mount_path (mountpoint));
301       if (drive)
302         {
303           _g_unix_drive_disconnected (drive);
304           monitor->drives = g_list_remove (monitor->drives, drive);
305           g_signal_emit_by_name (monitor, "drive_disconnected", drive);
306           g_object_unref (drive);
307         }
308     }
309   
310   for (l = added; l != NULL; l = l->next)
311     {
312       GUnixMountPoint *mountpoint = l->data;
313       
314       drive = _g_unix_drive_new (G_VOLUME_MONITOR (monitor), mountpoint);
315       if (drive)
316         {
317           monitor->drives = g_list_prepend (monitor->drives, drive);
318           g_signal_emit_by_name (monitor, "drive_connected", drive);
319         }
320     }
321   
322   g_list_free (added);
323   g_list_free (removed);
324   g_list_foreach (monitor->last_mountpoints,
325                   (GFunc)g_unix_mount_point_free, NULL);
326   g_list_free (monitor->last_mountpoints);
327   monitor->last_mountpoints = new_mountpoints;
328 }
329
330 static void
331 update_volumes (GUnixVolumeMonitor *monitor)
332 {
333   GList *new_mounts;
334   GList *removed, *added;
335   GList *l;
336   GUnixVolume *volume;
337   GUnixDrive *drive;
338   const char *mount_path;
339   
340   new_mounts = g_get_unix_mounts (NULL);
341   
342   new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
343   
344   diff_sorted_lists (monitor->last_mounts,
345                      new_mounts, (GCompareFunc) g_unix_mount_compare,
346                      &added, &removed);
347   
348   for (l = removed; l != NULL; l = l->next)
349     {
350       GUnixMount *mount = l->data;
351       
352       volume = find_volume_by_mountpoint (monitor, g_unix_mount_get_mount_path (mount));
353       if (volume)
354         {
355           _g_unix_volume_unmounted (volume);
356           monitor->volumes = g_list_remove (monitor->volumes, volume);
357           g_signal_emit_by_name (monitor, "volume_unmounted", volume);
358           g_object_unref (volume);
359         }
360     }
361   
362   for (l = added; l != NULL; l = l->next)
363     {
364       GUnixMount *mount = l->data;
365
366       mount_path = g_unix_mount_get_mount_path (mount);
367       
368       drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor,
369                                                                  mount_path);
370       volume = _g_unix_volume_new (mount, drive);
371       if (volume)
372         {
373           monitor->volumes = g_list_prepend (monitor->volumes, volume);
374           g_signal_emit_by_name (monitor, "volume_mounted", volume);
375         }
376     }
377   
378   g_list_free (added);
379   g_list_free (removed);
380   g_list_foreach (monitor->last_mounts,
381                   (GFunc)g_unix_mount_free, NULL);
382   g_list_free (monitor->last_mounts);
383   monitor->last_mounts = new_mounts;
384 }