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