1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Brasero
4  * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5  *
6  * Libbrasero-media is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * The Libbrasero-media authors hereby grant permission for non-GPL compatible
12  * GStreamer plugins to be used and distributed together with GStreamer
13  * and Libbrasero-media. This permission is above and beyond the permissions granted
14  * by the GPL license by which Libbrasero-media is covered. If you modify this code
15  * you may extend this exception to your version of the code, but you are not
16  * obligated to do so. If you do not wish to do so, delete this exception
17  * statement from your version.
18  *
19  * Libbrasero-media is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to:
26  * 	The Free Software Foundation, Inc.,
27  * 	51 Franklin Street, Fifth Floor
28  * 	Boston, MA  02110-1301, USA.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34 
35 #include <string.h>
36 
37 #include <glib.h>
38 #include <glib/gi18n-lib.h>
39 
40 #include <gio/gio.h>
41 
42 #include "brasero-media-private.h"
43 #include "brasero-volume.h"
44 #include "brasero-gio-operation.h"
45 
46 typedef struct _BraseroVolumePrivate BraseroVolumePrivate;
47 struct _BraseroVolumePrivate
48 {
49 	GCancellable *cancel;
50 };
51 
52 #define BRASERO_VOLUME_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VOLUME, BraseroVolumePrivate))
53 
54 G_DEFINE_TYPE (BraseroVolume, brasero_volume, BRASERO_TYPE_MEDIUM);
55 
56 /**
57  * brasero_volume_get_gvolume:
58  * @volume: #BraseroVolume
59  *
60  * Gets the corresponding #GVolume for @volume.
61  *
62  * Return value: a #GVolume *.
63  *
64  **/
65 GVolume *
brasero_volume_get_gvolume(BraseroVolume * volume)66 brasero_volume_get_gvolume (BraseroVolume *volume)
67 {
68 	const gchar *volume_path = NULL;
69 	GVolumeMonitor *monitor;
70 	GVolume *gvolume = NULL;
71 	BraseroDrive *drive;
72 	GList *volumes;
73 	GList *iter;
74 
75 	g_return_val_if_fail (volume != NULL, NULL);
76 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), NULL);
77 
78 	drive = brasero_medium_get_drive (BRASERO_MEDIUM (volume));
79 
80 	/* This returns the block device which is the
81 	 * same as the device for all OSes except
82 	 * Solaris where the device is the raw device. */
83 	volume_path = brasero_drive_get_block_device (drive);
84 
85 	/* NOTE: medium-monitor already holds a reference for GVolumeMonitor */
86 	monitor = g_volume_monitor_get ();
87 	volumes = g_volume_monitor_get_volumes (monitor);
88 	g_object_unref (monitor);
89 
90 	for (iter = volumes; iter; iter = iter->next) {
91 		gchar *device_path;
92 		GVolume *tmp;
93 
94 		tmp = iter->data;
95 		device_path = g_volume_get_identifier (tmp, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
96 		if (!device_path)
97 			continue;
98 
99 		BRASERO_MEDIA_LOG ("Found volume %s", device_path);
100 		if (!strcmp (device_path, volume_path)) {
101 			gvolume = tmp;
102 			g_free (device_path);
103 			g_object_ref (gvolume);
104 			break;
105 		}
106 
107 		g_free (device_path);
108 	}
109 	g_list_foreach (volumes, (GFunc) g_object_unref, NULL);
110 	g_list_free (volumes);
111 
112 	if (!gvolume)
113 		BRASERO_MEDIA_LOG ("No volume found for medium");
114 
115 	return gvolume;
116 }
117 
118 /**
119  * brasero_volume_is_mounted:
120  * @volume: #BraseroVolume
121  *
122  * Returns whether the volume is currently mounted.
123  *
124  * Return value: a #gboolean. TRUE if it is mounted.
125  *
126  **/
127 gboolean
brasero_volume_is_mounted(BraseroVolume * volume)128 brasero_volume_is_mounted (BraseroVolume *volume)
129 {
130 	gchar *path;
131 
132 	g_return_val_if_fail (volume != NULL, FALSE);
133 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), FALSE);
134 
135 	/* NOTE: that's the surest way to know if a drive is really mounted. For
136 	 * GIO a blank medium can be mounted to burn:/// which is not really
137 	 * what we're interested in. So the mount path must be also local. */
138 	path = brasero_volume_get_mount_point (volume, NULL);
139 	if (path) {
140 		g_free (path);
141 		return TRUE;
142 	}
143 
144 	return FALSE;
145 }
146 
147 /**
148  * brasero_volume_get_mount_point:
149  * @volume: #BraseroVolume
150  * @error: #GError **
151  *
152  * Returns the path for mount point for @volume.
153  *
154  * Return value: a #gchar *
155  *
156  **/
157 gchar *
brasero_volume_get_mount_point(BraseroVolume * volume,GError ** error)158 brasero_volume_get_mount_point (BraseroVolume *volume,
159 				GError **error)
160 {
161 	gchar *local_path = NULL;
162 	GVolume *gvolume;
163 	GMount *mount;
164 	GFile *root;
165 
166 	g_return_val_if_fail (volume != NULL, NULL);
167 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), NULL);
168 
169 	gvolume = brasero_volume_get_gvolume (volume);
170 	if (!gvolume)
171 		return NULL;
172 
173 	/* get the uri for the mount point */
174 	mount = g_volume_get_mount (gvolume);
175 	g_object_unref (gvolume);
176 	if (!mount)
177 		return NULL;
178 
179 	root = g_mount_get_root (mount);
180 	g_object_unref (mount);
181 
182 	if (!root) {
183 		g_set_error (error,
184 			     BRASERO_MEDIA_ERROR,
185 			     BRASERO_MEDIA_ERROR_GENERAL,
186 			     _("The disc mount point could not be retrieved"));
187 	}
188 	else {
189 		local_path = g_file_get_path (root);
190 		g_object_unref (root);
191 		BRASERO_MEDIA_LOG ("Mount point is %s", local_path);
192 	}
193 
194 	return local_path;
195 }
196 
197 /**
198  * brasero_volume_umount:
199  * @volume: #BraseroVolume
200  * @wait: #gboolean
201  * @error: #GError **
202  *
203  * Unmount @volume. If wait is set to TRUE, then block (in a GMainLoop) until
204  * the operation finishes.
205  *
206  * Return value: a #gboolean. TRUE if the operation succeeded.
207  *
208  **/
209 gboolean
brasero_volume_umount(BraseroVolume * volume,gboolean wait,GError ** error)210 brasero_volume_umount (BraseroVolume *volume,
211 		       gboolean wait,
212 		       GError **error)
213 {
214 	gboolean result;
215 	GVolume *gvolume;
216 	BraseroVolumePrivate *priv;
217 
218 	if (!volume)
219 		return TRUE;
220 
221 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), FALSE);
222 
223 	priv = BRASERO_VOLUME_PRIVATE (volume);
224 
225 	gvolume = brasero_volume_get_gvolume (volume);
226 	if (!gvolume)
227 		return TRUE;
228 
229 	if (g_cancellable_is_cancelled (priv->cancel)) {
230 		BRASERO_MEDIA_LOG ("Resetting GCancellable object");
231 		g_cancellable_reset (priv->cancel);
232 	}
233 
234 	result = brasero_gio_operation_umount (gvolume,
235 					       priv->cancel,
236 					       wait,
237 					       error);
238 	g_object_unref (gvolume);
239 
240 	return result;
241 }
242 
243 /**
244  * brasero_volume_mount:
245  * @volume: #BraseroVolume *
246  * @parent_window: #GtkWindow *
247  * @wait: #gboolean
248  * @error: #GError **
249  *
250  * Mount @volume. If wait is set to TRUE, then block (in a GMainLoop) until
251  * the operation finishes.
252  * @parent_window is used if an authentification is needed. Then the authentification
253  * dialog will be set modal.
254  *
255  * Return value: a #gboolean. TRUE if the operation succeeded.
256  *
257  **/
258 gboolean
brasero_volume_mount(BraseroVolume * volume,GtkWindow * parent_window,gboolean wait,GError ** error)259 brasero_volume_mount (BraseroVolume *volume,
260 		      GtkWindow *parent_window,
261 		      gboolean wait,
262 		      GError **error)
263 {
264 	gboolean result;
265 	GVolume *gvolume;
266 	BraseroVolumePrivate *priv;
267 
268 	if (!volume)
269 		return TRUE;
270 
271 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), FALSE);
272 
273 	priv = BRASERO_VOLUME_PRIVATE (volume);
274 
275 	gvolume = brasero_volume_get_gvolume (volume);
276 	if (!gvolume)
277 		return TRUE;
278 
279 	if (g_cancellable_is_cancelled (priv->cancel)) {
280 		BRASERO_MEDIA_LOG ("Resetting GCancellable object");
281 		g_cancellable_reset (priv->cancel);
282 	}
283 
284 	result = brasero_gio_operation_mount (gvolume,
285 					      parent_window,
286 					      priv->cancel,
287 					      wait,
288 					      error);
289 	g_object_unref (gvolume);
290 
291 	return result;
292 }
293 
294 /**
295  * brasero_volume_cancel_current_operation:
296  * @volume: #BraseroVolume *
297  *
298  * Cancels all operations currently running for @volume
299  *
300  **/
301 void
brasero_volume_cancel_current_operation(BraseroVolume * volume)302 brasero_volume_cancel_current_operation (BraseroVolume *volume)
303 {
304 	BraseroVolumePrivate *priv;
305 
306 	g_return_if_fail (volume != NULL);
307 	g_return_if_fail (BRASERO_IS_VOLUME (volume));
308 
309 	priv = BRASERO_VOLUME_PRIVATE (volume);
310 
311 	BRASERO_MEDIA_LOG ("Cancelling volume operation");
312 
313 	g_cancellable_cancel (priv->cancel);
314 }
315 
316 /**
317  * brasero_volume_get_icon:
318  * @volume: #BraseroVolume *
319  *
320  * Returns a GIcon pointer for the volume.
321  *
322  * Return value: a #GIcon*
323  *
324  **/
325 GIcon *
brasero_volume_get_icon(BraseroVolume * volume)326 brasero_volume_get_icon (BraseroVolume *volume)
327 {
328 	GVolume *gvolume;
329 	GMount *mount;
330 	GIcon *icon;
331 
332 	if (!volume)
333 		return g_themed_icon_new_with_default_fallbacks ("drive-optical");
334 
335 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), NULL);
336 
337 	if (brasero_medium_get_status (BRASERO_MEDIUM (volume)) == BRASERO_MEDIUM_FILE)
338 		return g_themed_icon_new_with_default_fallbacks ("iso-image-new");
339 
340 	gvolume = brasero_volume_get_gvolume (volume);
341 	if (!gvolume)
342 		return g_themed_icon_new_with_default_fallbacks ("drive-optical");
343 
344 	mount = g_volume_get_mount (gvolume);
345 	if (mount) {
346 		icon = g_mount_get_icon (mount);
347 		g_object_unref (mount);
348 	}
349 	else
350 		icon = g_volume_get_icon (gvolume);
351 
352 	g_object_unref (gvolume);
353 
354 	return icon;
355 }
356 
357 /**
358  * brasero_volume_get_name:
359  * @volume: #BraseroVolume *
360  *
361  * Returns a string that can be displayed to represent the volume²
362  *
363  * Return value: a #gchar *. Free when not needed anymore.
364  *
365  **/
366 gchar *
brasero_volume_get_name(BraseroVolume * volume)367 brasero_volume_get_name (BraseroVolume *volume)
368 {
369 	BraseroMedia media;
370 	const gchar *type;
371 	GVolume *gvolume;
372 	gchar *name;
373 
374 	g_return_val_if_fail (volume != NULL, NULL);
375 	g_return_val_if_fail (BRASERO_IS_VOLUME (volume), NULL);
376 
377 	media = brasero_medium_get_status (BRASERO_MEDIUM (volume));
378 	if (media & BRASERO_MEDIUM_FILE) {
379 		/* Translators: This is a fake drive, a file, and means that
380 		 * when we're writing, we're writing to a file and create an
381 		 * image on the hard drive. */
382 		return g_strdup (_("Image File"));
383 	}
384 
385 	if (media & BRASERO_MEDIUM_HAS_AUDIO) {
386 		const gchar *audio_name;
387 
388 		audio_name = brasero_medium_get_CD_TEXT_title (BRASERO_MEDIUM (volume));
389 		if (audio_name)
390 			return g_strdup (audio_name);
391 	}
392 
393 	gvolume = brasero_volume_get_gvolume (volume);
394 	if (!gvolume)
395 		goto last_chance;
396 
397 	name = g_volume_get_name (gvolume);
398 	g_object_unref (gvolume);
399 
400 	if (name)
401 		return name;
402 
403 last_chance:
404 
405 	type = brasero_medium_get_type_string (BRASERO_MEDIUM (volume));
406 	name = NULL;
407 	if (media & BRASERO_MEDIUM_BLANK) {
408 		/* NOTE for translators: the first %s is the disc type and Blank is an adjective. */
409 		name = g_strdup_printf (_("Blank disc (%s)"), type);
410 	}
411 	else if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_HAS_AUDIO|BRASERO_MEDIUM_HAS_DATA)) {
412 		/* NOTE for translators: the first %s is the disc type. */
413 		name = g_strdup_printf (_("Audio and data disc (%s)"), type);
414 	}
415 	else if (media & BRASERO_MEDIUM_HAS_AUDIO) {
416 		/* NOTE for translators: the first %s is the disc type. */
417 		name = g_strdup_printf (_("Audio disc (%s)"), type);
418 	}
419 	else if (media & BRASERO_MEDIUM_HAS_DATA) {
420 		/* NOTE for translators: the first %s is the disc type. */
421 		name = g_strdup_printf (_("Data disc (%s)"), type);
422 	}
423 	else {
424 		name = g_strdup (type);
425 	}
426 
427 	return name;
428 }
429 
430 static void
brasero_volume_init(BraseroVolume * object)431 brasero_volume_init (BraseroVolume *object)
432 {
433 	BraseroVolumePrivate *priv;
434 
435 	priv = BRASERO_VOLUME_PRIVATE (object);
436 	priv->cancel = g_cancellable_new ();
437 }
438 
439 static void
brasero_volume_finalize(GObject * object)440 brasero_volume_finalize (GObject *object)
441 {
442 	BraseroVolumePrivate *priv;
443 
444 	priv = BRASERO_VOLUME_PRIVATE (object);
445 
446 	BRASERO_MEDIA_LOG ("Finalizing Volume object");
447 	if (priv->cancel) {
448 		g_cancellable_cancel (priv->cancel);
449 		g_object_unref (priv->cancel);
450 		priv->cancel = NULL;
451 	}
452 
453 	G_OBJECT_CLASS (brasero_volume_parent_class)->finalize (object);
454 }
455 
456 static void
brasero_volume_class_init(BraseroVolumeClass * klass)457 brasero_volume_class_init (BraseroVolumeClass *klass)
458 {
459 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
460 
461 	g_type_class_add_private (klass, sizeof (BraseroVolumePrivate));
462 
463 	object_class->finalize = brasero_volume_finalize;
464 }
465