1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* GIO - GLib Input, Output and Streaming Library
3 *
4 * Copyright (C) 2006-2007 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 * Author: David Zeuthen <davidz@redhat.com>
22 */
23
24 #include <config.h>
25
26 #include <string.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29
30 #include <glib.h>
31 #include <glib/gi18n-lib.h>
32 #include <gio/gio.h>
33
34 #include "ggphoto2volume.h"
35
36 #include "gvfsgphoto2utils.h"
37
38 /* Protects all fields of GHalDrive that can change */
39 G_LOCK_DEFINE_STATIC(gphoto2_volume);
40
41 struct _GGPhoto2Volume {
42 GObject parent;
43
44 GVolumeMonitor *volume_monitor; /* owned by volume monitor */
45
46 char *device_path;
47 GUdevDevice *device;
48
49 GFile *activation_root;
50
51 char *name;
52 char *icon;
53 char *symbolic_icon;
54 };
55
56 static void g_gphoto2_volume_volume_iface_init (GVolumeIface *iface);
57
58 G_DEFINE_TYPE_EXTENDED (GGPhoto2Volume, g_gphoto2_volume, G_TYPE_OBJECT, 0,
59 G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
60 g_gphoto2_volume_volume_iface_init))
61
62 static void
g_gphoto2_volume_finalize(GObject * object)63 g_gphoto2_volume_finalize (GObject *object)
64 {
65 GGPhoto2Volume *volume;
66
67 volume = G_GPHOTO2_VOLUME (object);
68
69 if (volume->device != NULL)
70 g_object_unref (volume->device);
71
72 if (volume->activation_root != NULL)
73 g_object_unref (volume->activation_root);
74
75 if (volume->volume_monitor != NULL)
76 g_object_remove_weak_pointer (G_OBJECT (volume->volume_monitor), (gpointer) &(volume->volume_monitor));
77
78 g_free (volume->name);
79 g_free (volume->icon);
80 g_free (volume->symbolic_icon);
81
82 if (G_OBJECT_CLASS (g_gphoto2_volume_parent_class)->finalize)
83 (*G_OBJECT_CLASS (g_gphoto2_volume_parent_class)->finalize) (object);
84 }
85
86 static void
g_gphoto2_volume_class_init(GGPhoto2VolumeClass * klass)87 g_gphoto2_volume_class_init (GGPhoto2VolumeClass *klass)
88 {
89 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
90
91 gobject_class->finalize = g_gphoto2_volume_finalize;
92 }
93
94 static void
g_gphoto2_volume_init(GGPhoto2Volume * gphoto2_volume)95 g_gphoto2_volume_init (GGPhoto2Volume *gphoto2_volume)
96 {
97 }
98
99 GGPhoto2Volume *
g_gphoto2_volume_new(GVolumeMonitor * volume_monitor,GUdevDevice * device,GUdevClient * gudev_client,GFile * activation_root)100 g_gphoto2_volume_new (GVolumeMonitor *volume_monitor,
101 GUdevDevice *device,
102 GUdevClient *gudev_client,
103 GFile *activation_root)
104 {
105 GGPhoto2Volume *volume;
106 const char *device_path;
107
108 g_return_val_if_fail (volume_monitor != NULL, NULL);
109 g_return_val_if_fail (device != NULL, NULL);
110 g_return_val_if_fail (gudev_client != NULL, NULL);
111 g_return_val_if_fail (activation_root != NULL, NULL);
112
113 if (!g_udev_device_has_property (device, "ID_GPHOTO2"))
114 return NULL;
115 device_path = g_udev_device_get_device_file (device);
116
117 volume = g_object_new (G_TYPE_GPHOTO2_VOLUME, NULL);
118 volume->volume_monitor = volume_monitor;
119 g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
120 volume->device_path = g_strdup (device_path);
121 volume->device = g_object_ref (device);
122 volume->activation_root = g_object_ref (activation_root);
123
124 volume->name = g_vfs_get_volume_name (device, "ID_GPHOTO2");
125 volume->icon = g_vfs_get_volume_icon (device);
126 volume->symbolic_icon = g_vfs_get_volume_symbolic_icon (device);
127 /* we do not really need to listen for changes */
128
129 return volume;
130 }
131
132 void
g_gphoto2_volume_removed(GGPhoto2Volume * volume)133 g_gphoto2_volume_removed (GGPhoto2Volume *volume)
134 {
135 ;
136 }
137
138 static GIcon *
g_gphoto2_volume_get_icon(GVolume * volume)139 g_gphoto2_volume_get_icon (GVolume *volume)
140 {
141 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
142 GIcon *icon;
143
144 G_LOCK (gphoto2_volume);
145 icon = g_themed_icon_new (gphoto2_volume->icon);
146 G_UNLOCK (gphoto2_volume);
147 return icon;
148 }
149
150 static GIcon *
g_gphoto2_volume_get_symbolic_icon(GVolume * volume)151 g_gphoto2_volume_get_symbolic_icon (GVolume *volume)
152 {
153 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
154 GIcon *icon;
155
156 G_LOCK (gphoto2_volume);
157 icon = g_themed_icon_new_with_default_fallbacks (gphoto2_volume->symbolic_icon);
158 G_UNLOCK (gphoto2_volume);
159 return icon;
160 }
161
162 static char *
g_gphoto2_volume_get_name(GVolume * volume)163 g_gphoto2_volume_get_name (GVolume *volume)
164 {
165 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
166 char *name;
167
168 G_LOCK (gphoto2_volume);
169 name = g_strdup (gphoto2_volume->name);
170 G_UNLOCK (gphoto2_volume);
171
172 return name;
173 }
174
175 static char *
g_gphoto2_volume_get_uuid(GVolume * volume)176 g_gphoto2_volume_get_uuid (GVolume *volume)
177 {
178 return NULL;
179 }
180
181 static gboolean
g_gphoto2_volume_can_mount(GVolume * volume)182 g_gphoto2_volume_can_mount (GVolume *volume)
183 {
184 return TRUE;
185 }
186
187 static gboolean
g_gphoto2_volume_can_eject(GVolume * volume)188 g_gphoto2_volume_can_eject (GVolume *volume)
189 {
190 return FALSE;
191 }
192
193 static gboolean
g_gphoto2_volume_should_automount(GVolume * volume)194 g_gphoto2_volume_should_automount (GVolume *volume)
195 {
196 return TRUE;
197 }
198
199 static GDrive *
g_gphoto2_volume_get_drive(GVolume * volume)200 g_gphoto2_volume_get_drive (GVolume *volume)
201 {
202 return NULL;
203 }
204
205 static GMount *
g_gphoto2_volume_get_mount(GVolume * volume)206 g_gphoto2_volume_get_mount (GVolume *volume)
207 {
208 return NULL;
209 }
210
211 gboolean
g_gphoto2_volume_has_path(GGPhoto2Volume * volume,const char * sysfs_path)212 g_gphoto2_volume_has_path (GGPhoto2Volume *volume,
213 const char *sysfs_path)
214 {
215 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
216 gboolean res;
217
218 G_LOCK (gphoto2_volume);
219 res = FALSE;
220 if (gphoto2_volume->device != NULL)
221 res = g_strcmp0 (g_udev_device_get_sysfs_path (gphoto2_volume->device), sysfs_path) == 0;
222 G_UNLOCK (gphoto2_volume);
223 return res;
224 }
225
226 typedef struct
227 {
228 GGPhoto2Volume *enclosing_volume;
229 GAsyncReadyCallback callback;
230 gpointer user_data;
231 } ActivationMountOp;
232
233 static void
mount_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)234 mount_callback (GObject *source_object,
235 GAsyncResult *res,
236 gpointer user_data)
237 {
238 ActivationMountOp *data = user_data;
239 data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
240 g_free (data);
241 }
242
243 static void
g_gphoto2_volume_mount(GVolume * volume,GMountMountFlags flags,GMountOperation * mount_operation,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)244 g_gphoto2_volume_mount (GVolume *volume,
245 GMountMountFlags flags,
246 GMountOperation *mount_operation,
247 GCancellable *cancellable,
248 GAsyncReadyCallback callback,
249 gpointer user_data)
250 {
251 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
252 ActivationMountOp *data;
253
254 /*g_warning ("gphoto2_volume_mount (can_mount=%d foreign=%p device_path=%s)",
255 g_gphoto2_volume_can_mount (volume),
256 gphoto2_volume->activation_root,
257 gphoto2_volume->device_path);*/
258
259 G_LOCK (gphoto2_volume);
260
261 data = g_new0 (ActivationMountOp, 1);
262 data->enclosing_volume = gphoto2_volume;
263 data->callback = callback;
264 data->user_data = user_data;
265
266 g_file_mount_enclosing_volume (gphoto2_volume->activation_root,
267 0,
268 mount_operation,
269 cancellable,
270 mount_callback,
271 data);
272
273 G_UNLOCK (gphoto2_volume);
274 }
275
276 static gboolean
g_gphoto2_volume_mount_finish(GVolume * volume,GAsyncResult * result,GError ** error)277 g_gphoto2_volume_mount_finish (GVolume *volume,
278 GAsyncResult *result,
279 GError **error)
280 {
281 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
282 gboolean res;
283
284 G_LOCK (gphoto2_volume);
285 res = g_file_mount_enclosing_volume_finish (gphoto2_volume->activation_root, result, error);
286 G_UNLOCK (gphoto2_volume);
287
288 return res;
289 }
290
291 static char *
g_gphoto2_volume_get_identifier(GVolume * volume,const char * kind)292 g_gphoto2_volume_get_identifier (GVolume *volume,
293 const char *kind)
294 {
295 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
296 char *id;
297
298 G_LOCK (gphoto2_volume);
299 id = NULL;
300 if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
301 id = g_strdup (gphoto2_volume->device_path);
302 G_UNLOCK (gphoto2_volume);
303
304 return id;
305 }
306
307 static char **
g_gphoto2_volume_enumerate_identifiers(GVolume * volume)308 g_gphoto2_volume_enumerate_identifiers (GVolume *volume)
309 {
310 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
311 GPtrArray *res;
312
313 G_LOCK (gphoto2_volume);
314
315 res = g_ptr_array_new ();
316
317 if (gphoto2_volume->device_path && *gphoto2_volume->device_path != 0)
318 g_ptr_array_add (res,
319 g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
320
321 /* Null-terminate */
322 g_ptr_array_add (res, NULL);
323
324 G_UNLOCK (gphoto2_volume);
325
326 return (char **)g_ptr_array_free (res, FALSE);
327 }
328
329 static GFile *
g_gphoto2_volume_get_activation_root(GVolume * volume)330 g_gphoto2_volume_get_activation_root (GVolume *volume)
331 {
332 GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
333
334 return g_object_ref (gphoto2_volume->activation_root);
335 }
336
337 static void
g_gphoto2_volume_volume_iface_init(GVolumeIface * iface)338 g_gphoto2_volume_volume_iface_init (GVolumeIface *iface)
339 {
340 iface->get_name = g_gphoto2_volume_get_name;
341 iface->get_icon = g_gphoto2_volume_get_icon;
342 iface->get_symbolic_icon = g_gphoto2_volume_get_symbolic_icon;
343 iface->get_uuid = g_gphoto2_volume_get_uuid;
344 iface->get_drive = g_gphoto2_volume_get_drive;
345 iface->get_mount = g_gphoto2_volume_get_mount;
346 iface->can_mount = g_gphoto2_volume_can_mount;
347 iface->can_eject = g_gphoto2_volume_can_eject;
348 iface->should_automount = g_gphoto2_volume_should_automount;
349 iface->mount_fn = g_gphoto2_volume_mount;
350 iface->mount_finish = g_gphoto2_volume_mount_finish;
351 iface->eject = NULL;
352 iface->eject_finish = NULL;
353 iface->get_identifier = g_gphoto2_volume_get_identifier;
354 iface->enumerate_identifiers = g_gphoto2_volume_enumerate_identifiers;
355 iface->get_activation_root = g_gphoto2_volume_get_activation_root;
356 }
357