1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Libbrasero-media
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 <unistd.h>
36 #include <string.h>
37 
38 #ifdef HAVE_CAM_LIB_H
39 #include <errno.h>
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <camlib.h>
43 #endif
44 
45 #include <glib.h>
46 #include <glib-object.h>
47 #include <glib/gi18n-lib.h>
48 
49 #include <gio/gio.h>
50 
51 #include "brasero-media-private.h"
52 #include "brasero-gio-operation.h"
53 
54 #include "brasero-medium.h"
55 #include "brasero-volume.h"
56 #include "brasero-drive.h"
57 
58 #include "brasero-drive-priv.h"
59 #include "scsi-device.h"
60 #include "scsi-utils.h"
61 #include "scsi-spc1.h"
62 #include "scsi-mmc1.h"
63 #include "scsi-mmc2.h"
64 #include "scsi-status-page.h"
65 #include "scsi-mode-pages.h"
66 #include "scsi-sbc.h"
67 
68 typedef struct _BraseroDrivePrivate BraseroDrivePrivate;
69 struct _BraseroDrivePrivate
70 {
71 	GDrive *gdrive;
72 
73 	GThread *probe;
74 	GMutex *mutex;
75 	GCond *cond;
76 	GCond *cond_probe;
77 	gint probe_id;
78 
79 	BraseroMedium *medium;
80 	BraseroDriveCaps caps;
81 
82 	gchar *udi;
83 
84 	gchar *name;
85 
86 	gchar *device;
87 	gchar *block_device;
88 
89 	GCancellable *cancel;
90 
91 	guint initial_probe:1;
92 	guint initial_probe_cancelled:1;
93 
94 	guint has_medium:1;
95 	guint probe_cancelled:1;
96 
97 	guint locked:1;
98 	guint ejecting:1;
99 	guint probe_waiting:1;
100 };
101 
102 #define BRASERO_DRIVE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DRIVE, BraseroDrivePrivate))
103 
104 enum {
105 	MEDIUM_REMOVED,
106 	MEDIUM_INSERTED,
107 	LAST_SIGNAL
108 };
109 static gulong drive_signals [LAST_SIGNAL] = {0, };
110 
111 enum {
112 	PROP_NONE	= 0,
113 	PROP_DEVICE,
114 	PROP_GDRIVE,
115 	PROP_UDI
116 };
117 
118 G_DEFINE_TYPE (BraseroDrive, brasero_drive, G_TYPE_OBJECT);
119 
120 #define BRASERO_DRIVE_OPEN_ATTEMPTS			5
121 
122 static void
123 brasero_drive_probe_inside (BraseroDrive *drive);
124 
125 /**
126  * brasero_drive_get_gdrive:
127  * @drive: a #BraseroDrive
128  *
129  * Returns the #GDrive corresponding to this #BraseroDrive
130  *
131  * Return value: a #GDrive or NULL. Unref after use.
132  **/
133 GDrive *
brasero_drive_get_gdrive(BraseroDrive * drive)134 brasero_drive_get_gdrive (BraseroDrive *drive)
135 {
136 	BraseroDrivePrivate *priv;
137 
138 	g_return_val_if_fail (drive != NULL, NULL);
139 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
140 
141 	if (brasero_drive_is_fake (drive))
142 		return NULL;
143 
144 	priv = BRASERO_DRIVE_PRIVATE (drive);
145 
146 	if (!priv->gdrive)
147 		return NULL;
148 
149 	return g_object_ref (priv->gdrive);
150 }
151 
152 /**
153  * brasero_drive_can_eject:
154  * @drive: #BraseroDrive
155  *
156  * Returns whether the drive can eject media.
157  *
158  * Return value: a #gboolean. TRUE if the media can be ejected, FALSE otherwise.
159  *
160  **/
161 gboolean
brasero_drive_can_eject(BraseroDrive * drive)162 brasero_drive_can_eject (BraseroDrive *drive)
163 {
164 	GVolume *volume;
165 	gboolean result;
166 	BraseroDrivePrivate *priv;
167 
168 	g_return_val_if_fail (drive != NULL, FALSE);
169 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
170 
171 	priv = BRASERO_DRIVE_PRIVATE (drive);
172 
173 	if (!priv->gdrive) {
174 		BRASERO_MEDIA_LOG ("No GDrive");
175 		goto last_resort;
176 	}
177 
178 	if (!g_drive_can_eject (priv->gdrive)) {
179 		BRASERO_MEDIA_LOG ("GDrive can't eject");
180 		goto last_resort;
181 	}
182 
183 	return TRUE;
184 
185 last_resort:
186 
187 	if (!priv->medium)
188 		return FALSE;
189 
190 	/* last resort */
191 	volume = brasero_volume_get_gvolume (BRASERO_VOLUME (priv->medium));
192 	if (!volume)
193 		return FALSE;
194 
195 	result = g_volume_can_eject (volume);
196 	g_object_unref (volume);
197 
198 	return result;
199 }
200 
201 static void
brasero_drive_cancel_probing(BraseroDrive * drive)202 brasero_drive_cancel_probing (BraseroDrive *drive)
203 {
204 	BraseroDrivePrivate *priv;
205 
206 	priv = BRASERO_DRIVE_PRIVATE (drive);
207 
208 	priv->probe_waiting = FALSE;
209 
210 	g_mutex_lock (priv->mutex);
211 	if (priv->probe) {
212 		/* This to signal that we are cancelling */
213 		priv->probe_cancelled = TRUE;
214 		priv->initial_probe_cancelled = TRUE;
215 
216 		/* This is to wake up the thread if it
217 		 * was asleep waiting to retry to get
218 		 * hold of a handle to probe the drive */
219 		g_cond_signal (priv->cond_probe);
220 
221 		g_cond_wait (priv->cond, priv->mutex);
222 	}
223 	g_mutex_unlock (priv->mutex);
224 
225 	if (priv->probe_id) {
226 		g_source_remove (priv->probe_id);
227 		priv->probe_id = 0;
228 	}
229 }
230 
231 static void
brasero_drive_wait_probing_thread(BraseroDrive * drive)232 brasero_drive_wait_probing_thread (BraseroDrive *drive)
233 {
234 	BraseroDrivePrivate *priv;
235 
236 	priv = BRASERO_DRIVE_PRIVATE (drive);
237 
238 	g_mutex_lock (priv->mutex);
239 	if (priv->probe) {
240 		/* This is to wake up the thread if it
241 		 * was asleep waiting to retry to get
242 		 * hold of a handle to probe the drive */
243 		g_cond_signal (priv->cond_probe);
244 		g_cond_wait (priv->cond, priv->mutex);
245 	}
246 	g_mutex_unlock (priv->mutex);
247 }
248 
249 /**
250  * brasero_drive_eject:
251  * @drive: #BraseroDrive
252  * @wait: #gboolean whether to wait for the completion of the operation (with a GMainLoop)
253  * @error: #GError
254  *
255  * Open the drive tray or ejects the media if there is any inside.
256  *
257  * Return value: a #gboolean. TRUE on success, FALSE otherwise.
258  *
259  **/
260 gboolean
brasero_drive_eject(BraseroDrive * drive,gboolean wait,GError ** error)261 brasero_drive_eject (BraseroDrive *drive,
262 		     gboolean wait,
263 		     GError **error)
264 {
265 	BraseroDrivePrivate *priv;
266 	GVolume *gvolume;
267 	gboolean res;
268 
269 	g_return_val_if_fail (drive != NULL, FALSE);
270 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
271 
272 	priv = BRASERO_DRIVE_PRIVATE (drive);
273 
274 	/* reset if needed */
275 	if (g_cancellable_is_cancelled (priv->cancel)) {
276 		BRASERO_MEDIA_LOG ("Resetting GCancellable object");
277 		g_cancellable_reset (priv->cancel);
278 	}
279 
280 	BRASERO_MEDIA_LOG ("Trying to eject drive");
281 	if (priv->gdrive) {
282 		/* Wait for any ongoing probing as it
283 		 * would prevent the door from being
284 		 * opened. */
285 		brasero_drive_wait_probing_thread (drive);
286 
287 		priv->ejecting = TRUE;
288 		res = brasero_gio_operation_eject_drive (priv->gdrive,
289 							 priv->cancel,
290 							 wait,
291 							 error);
292 		priv->ejecting = FALSE;
293 		if (priv->probe_waiting)
294 			brasero_drive_probe_inside (drive);
295 
296 		if (res)
297 			return TRUE;
298 
299 		if (g_cancellable_is_cancelled (priv->cancel))
300 			return FALSE;
301 	}
302 	else
303 		BRASERO_MEDIA_LOG ("No GDrive");
304 
305 	if (!priv->medium)
306 		return FALSE;
307 
308 	/* reset if needed */
309 	if (g_cancellable_is_cancelled (priv->cancel)) {
310 		BRASERO_MEDIA_LOG ("Resetting GCancellable object");
311 		g_cancellable_reset (priv->cancel);
312 	}
313 
314 	gvolume = brasero_volume_get_gvolume (BRASERO_VOLUME (priv->medium));
315 	if (gvolume) {
316 		BRASERO_MEDIA_LOG ("Trying to eject volume");
317 
318 		/* Cancel any ongoing probing as it
319 		 * would prevent the door from being
320 		 * opened. */
321 		brasero_drive_wait_probing_thread (drive);
322 
323 		priv->ejecting = TRUE;
324 		res = brasero_gio_operation_eject_volume (gvolume,
325 							  priv->cancel,
326 							  wait,
327 							  error);
328 
329 		priv->ejecting = FALSE;
330 		if (priv->probe_waiting)
331 			brasero_drive_probe_inside (drive);
332 
333 		g_object_unref (gvolume);
334 	}
335 
336 	return res;
337 }
338 
339 /**
340  * brasero_drive_cancel_current_operation:
341  * @drive: #BraseroDrive *
342  *
343  * Cancels all operations currently running for @drive
344  *
345  **/
346 void
brasero_drive_cancel_current_operation(BraseroDrive * drive)347 brasero_drive_cancel_current_operation (BraseroDrive *drive)
348 {
349 	BraseroDrivePrivate *priv;
350 
351 	g_return_if_fail (drive != NULL);
352 	g_return_if_fail (BRASERO_IS_DRIVE (drive));
353 
354 	priv = BRASERO_DRIVE_PRIVATE (drive);
355 
356 	BRASERO_MEDIA_LOG ("Cancelling GIO operation");
357 	g_cancellable_cancel (priv->cancel);
358 }
359 
360 /**
361  * brasero_drive_get_bus_target_lun_string:
362  * @drive: a #BraseroDrive
363  *
364  * Returns the bus, target, lun ("{bus},{target},{lun}") as a string which is
365  * sometimes needed by some backends like cdrecord.
366  *
367  * NOTE: that function returns either bus/target/lun or the device path
368  * according to OSes. Basically it returns bus/target/lun only for FreeBSD
369  * which is the only OS in need for that. For all others it returns the device
370  * path.
371  *
372  * Return value: a string or NULL. The string must be freed when not needed
373  *
374  **/
375 gchar *
brasero_drive_get_bus_target_lun_string(BraseroDrive * drive)376 brasero_drive_get_bus_target_lun_string (BraseroDrive *drive)
377 {
378 	g_return_val_if_fail (drive != NULL, NULL);
379 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
380 
381 	return brasero_device_get_bus_target_lun (brasero_drive_get_device (drive));
382 }
383 
384 /**
385  * brasero_drive_is_fake:
386  * @drive: a #BraseroDrive
387  *
388  * Returns whether or not the drive is a fake one. There is only one and
389  * corresponds to a file which is used when the user wants to burn to a file.
390  *
391  * Return value: %TRUE or %FALSE.
392  **/
393 gboolean
brasero_drive_is_fake(BraseroDrive * drive)394 brasero_drive_is_fake (BraseroDrive *drive)
395 {
396 	BraseroDrivePrivate *priv;
397 
398 	g_return_val_if_fail (drive != NULL, FALSE);
399 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
400 
401 	priv = BRASERO_DRIVE_PRIVATE (drive);
402 	return (priv->device == NULL);
403 }
404 
405 /**
406  * brasero_drive_is_door_open:
407  * @drive: a #BraseroDrive
408  *
409  * Returns whether or not the drive door is open.
410  *
411  * Return value: %TRUE or %FALSE.
412  **/
413 gboolean
brasero_drive_is_door_open(BraseroDrive * drive)414 brasero_drive_is_door_open (BraseroDrive *drive)
415 {
416 	const gchar *device;
417 	BraseroDrivePrivate *priv;
418 	BraseroDeviceHandle *handle;
419 	BraseroScsiMechStatusHdr hdr;
420 
421 	g_return_val_if_fail (drive != NULL, FALSE);
422 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
423 
424 	priv = BRASERO_DRIVE_PRIVATE (drive);
425 	if (!priv->device)
426 		return FALSE;
427 
428 	device = brasero_drive_get_device (drive);
429 	handle = brasero_device_handle_open (device, FALSE, NULL);
430 	if (!handle)
431 		return FALSE;
432 
433 	brasero_mmc1_mech_status (handle,
434 				  &hdr,
435 				  NULL);
436 
437 	brasero_device_handle_close (handle);
438 
439 	return hdr.door_open;
440 }
441 
442 /**
443  * brasero_drive_can_use_exclusively:
444  * @drive: a #BraseroDrive
445  *
446  * Returns whether or not the drive can be used exclusively, that is whether or
447  * not it is currently used by another application.
448  *
449  * Return value: %TRUE or %FALSE.
450  **/
451 gboolean
brasero_drive_can_use_exclusively(BraseroDrive * drive)452 brasero_drive_can_use_exclusively (BraseroDrive *drive)
453 {
454 	BraseroDeviceHandle *handle;
455 	const gchar *device;
456 
457 	g_return_val_if_fail (drive != NULL, FALSE);
458 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
459 
460 	device = brasero_drive_get_device (drive);
461 	handle = brasero_device_handle_open (device, TRUE, NULL);
462 	if (!handle)
463 		return FALSE;
464 
465 	brasero_device_handle_close (handle);
466 	return TRUE;
467 }
468 
469 /**
470  * brasero_drive_is_locked:
471  * @drive: a #BraseroDrive
472  * @reason: a #gchar or NULL. A string to indicate what the drive was locked for if return value is %TRUE
473  *
474  * Checks whether a #BraseroDrive is currently locked. Manual ejection shouldn't be possible any more.
475  *
476  * Since 2.29.0
477  *
478  * Return value: %TRUE if the drive is locked or %FALSE.
479  **/
480 gboolean
brasero_drive_is_locked(BraseroDrive * drive,gchar ** reason)481 brasero_drive_is_locked (BraseroDrive *drive,
482                          gchar **reason)
483 {
484 	BraseroDrivePrivate *priv;
485 
486 	g_return_val_if_fail (drive != NULL, FALSE);
487 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
488 
489 	priv = BRASERO_DRIVE_PRIVATE (drive);
490 	return priv->locked;
491 }
492 
493 /**
494  * brasero_drive_lock:
495  * @drive: a #BraseroDrive
496  * @reason: a string to indicate what the drive was locked for
497  * @reason_for_failure: a string (or NULL) to hold the reason why the locking failed
498  *
499  * Locks a #BraseroDrive. Manual ejection shouldn't be possible any more.
500  *
501  * Return value: %TRUE if the drive was successfully locked or %FALSE.
502  **/
503 gboolean
brasero_drive_lock(BraseroDrive * drive,const gchar * reason,gchar ** reason_for_failure)504 brasero_drive_lock (BraseroDrive *drive,
505 		    const gchar *reason,
506 		    gchar **reason_for_failure)
507 {
508 	BraseroDeviceHandle *handle;
509 	BraseroDrivePrivate *priv;
510 	const gchar *device;
511 	gboolean result;
512 
513 	g_return_val_if_fail (drive != NULL, FALSE);
514 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
515 
516 	priv = BRASERO_DRIVE_PRIVATE (drive);
517 	if (!priv->device)
518 		return FALSE;
519 
520 	device = brasero_drive_get_device (drive);
521 	handle = brasero_device_handle_open (device, FALSE, NULL);
522 	if (!handle)
523 		return FALSE;
524 
525 	result = (brasero_sbc_medium_removal (handle, 1, NULL) == BRASERO_SCSI_OK);
526 	if (result) {
527 		BRASERO_MEDIA_LOG ("Device locked");
528 		priv->locked = TRUE;
529 	}
530 	else
531 		BRASERO_MEDIA_LOG ("Device failed to lock");
532 
533 	brasero_device_handle_close (handle);
534 	return result;
535 }
536 
537 /**
538  * brasero_drive_unlock:
539  * @drive: a #BraseroDrive
540  *
541  * Unlocks a #BraseroDrive.
542  *
543  * Return value: %TRUE if the drive was successfully unlocked or %FALSE.
544  **/
545 gboolean
brasero_drive_unlock(BraseroDrive * drive)546 brasero_drive_unlock (BraseroDrive *drive)
547 {
548 	BraseroDeviceHandle *handle;
549 	BraseroDrivePrivate *priv;
550 	const gchar *device;
551 	gboolean result;
552 
553 	g_return_val_if_fail (drive != NULL, FALSE);
554 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
555 
556 	priv = BRASERO_DRIVE_PRIVATE (drive);
557 	if (!priv->device)
558 		return FALSE;
559 
560 	device = brasero_drive_get_device (drive);
561 	handle = brasero_device_handle_open (device, FALSE, NULL);
562 	if (!handle)
563 		return FALSE;
564 
565 	result = (brasero_sbc_medium_removal (handle, 0, NULL) == BRASERO_SCSI_OK);
566 	if (result) {
567 		BRASERO_MEDIA_LOG ("Device unlocked");
568 		priv->locked = FALSE;
569 
570 		if (priv->probe_waiting) {
571 			BRASERO_MEDIA_LOG ("Probe on hold");
572 
573 			/* A probe was waiting */
574 			brasero_drive_probe_inside (drive);
575 		}
576 	}
577 	else
578 		BRASERO_MEDIA_LOG ("Device failed to unlock");
579 
580 	brasero_device_handle_close (handle);
581 
582 	return result;
583 }
584 
585 /**
586  * brasero_drive_get_display_name:
587  * @drive: a #BraseroDrive
588  *
589  * Gets a string holding the name for the drive. That string can be then
590  * displayed in a user interface.
591  *
592  * Return value: a string holding the name
593  **/
594 gchar *
brasero_drive_get_display_name(BraseroDrive * drive)595 brasero_drive_get_display_name (BraseroDrive *drive)
596 {
597 	BraseroDrivePrivate *priv;
598 
599 	g_return_val_if_fail (drive != NULL, NULL);
600 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
601 
602 	priv = BRASERO_DRIVE_PRIVATE (drive);
603 	if (!priv->device) {
604 		/* Translators: This is a fake drive, a file, and means that
605 		 * when we're writing, we're writing to a file and create an
606 		 * image on the hard drive. */
607 		return g_strdup (_("Image File"));
608 	}
609 
610 	return g_strdup (priv->name);
611 }
612 
613 /**
614  * brasero_drive_get_device:
615  * @drive: a #BraseroDrive
616  *
617  * Gets a string holding the device path for the drive.
618  *
619  * Return value: a string holding the device path.
620  * On Solaris returns raw device.
621  **/
622 const gchar *
brasero_drive_get_device(BraseroDrive * drive)623 brasero_drive_get_device (BraseroDrive *drive)
624 {
625 	BraseroDrivePrivate *priv;
626 
627 	g_return_val_if_fail (drive != NULL, NULL);
628 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
629 
630 	priv = BRASERO_DRIVE_PRIVATE (drive);
631 	return priv->device;
632 }
633 
634 /**
635  * brasero_drive_get_block_device:
636  * @drive: a #BraseroDrive
637  *
638  * Gets a string holding the block device path for the drive. This can be used on
639  * some other OSes, like Solaris, for GIO operations instead of the device
640  * path.
641  *
642  * Solaris uses block device for GIO operations and
643  * uses raw device for system calls and backends
644  * like cdrtool.
645  *
646  * If such a path is not available, it returns the device path.
647  *
648  * Return value: a string holding the block device path
649  **/
650 const gchar *
brasero_drive_get_block_device(BraseroDrive * drive)651 brasero_drive_get_block_device (BraseroDrive *drive)
652 {
653 	BraseroDrivePrivate *priv;
654 
655 	g_return_val_if_fail (drive != NULL, NULL);
656 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
657 
658 	priv = BRASERO_DRIVE_PRIVATE (drive);
659 	return priv->block_device? priv->block_device:priv->device;
660 }
661 
662 /**
663  * brasero_drive_get_udi:
664  * @drive: a #BraseroDrive
665  *
666  * Gets a string holding the HAL udi corresponding to this device. It can be used
667  * to uniquely identify the drive.
668  *
669  * Return value: a string holding the HAL udi or NULL. Not to be freed
670  **/
671 const gchar *
brasero_drive_get_udi(BraseroDrive * drive)672 brasero_drive_get_udi (BraseroDrive *drive)
673 {
674 	BraseroDrivePrivate *priv;
675 
676 	if (!drive)
677 		return NULL;
678 
679 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
680 
681 	priv = BRASERO_DRIVE_PRIVATE (drive);
682 	if (!priv->device || !priv->gdrive)
683 		return NULL;
684 
685 	if (priv->udi)
686 		return priv->udi;
687 
688 	priv->udi = g_drive_get_identifier (priv->gdrive, G_VOLUME_IDENTIFIER_KIND_HAL_UDI);
689 	return priv->udi;
690 }
691 
692 /**
693  * brasero_drive_get_medium:
694  * @drive: a #BraseroDrive
695  *
696  * Gets the medium currently inserted in the drive. If there is no medium or if
697  * the medium is not probed yet then it returns NULL.
698  *
699  * Return value: (transfer none): a #BraseroMedium object or NULL. No need to unref after use.
700  **/
701 BraseroMedium *
brasero_drive_get_medium(BraseroDrive * drive)702 brasero_drive_get_medium (BraseroDrive *drive)
703 {
704 	BraseroDrivePrivate *priv;
705 
706 	if (!drive)
707 		return NULL;
708 
709 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), NULL);
710 
711 	priv = BRASERO_DRIVE_PRIVATE (drive);
712 	if (brasero_drive_probing (drive))
713 		return NULL;
714 
715 	return priv->medium;
716 }
717 
718 /**
719  * brasero_drive_get_caps:
720  * @drive: a #BraseroDrive
721  *
722  * Returns what type(s) of disc the drive can write to.
723  *
724  * Return value: a #BraseroDriveCaps.
725  **/
726 BraseroDriveCaps
brasero_drive_get_caps(BraseroDrive * drive)727 brasero_drive_get_caps (BraseroDrive *drive)
728 {
729 	BraseroDrivePrivate *priv;
730 
731 	g_return_val_if_fail (drive != NULL, BRASERO_DRIVE_CAPS_NONE);
732 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), BRASERO_DRIVE_CAPS_NONE);
733 
734 	priv = BRASERO_DRIVE_PRIVATE (drive);
735 	return priv->caps;
736 }
737 
738 /**
739  * brasero_drive_can_write_media:
740  * @drive: a #BraseroDrive
741  * @media: a #BraseroMedia
742  *
743  * Returns whether the disc can burn a specific media type.
744  *
745  * Since 2.29.0
746  *
747  * Return value: a #gboolean. TRUE if the drive can write this type of media and FALSE otherwise
748  **/
749 gboolean
brasero_drive_can_write_media(BraseroDrive * drive,BraseroMedia media)750 brasero_drive_can_write_media (BraseroDrive *drive,
751                                BraseroMedia media)
752 {
753 	BraseroDrivePrivate *priv;
754 
755 	g_return_val_if_fail (drive != NULL, FALSE);
756 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
757 
758 	priv = BRASERO_DRIVE_PRIVATE (drive);
759 
760 	if (!(media & BRASERO_MEDIUM_REWRITABLE)
761 	&&   (media & BRASERO_MEDIUM_CLOSED))
762 		return FALSE;
763 
764 	if (media & BRASERO_MEDIUM_FILE)
765 		return FALSE;
766 
767 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_CDR))
768 		return (priv->caps & BRASERO_DRIVE_CAPS_CDR) != 0;
769 
770 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDR))
771 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDR) != 0;
772 
773 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDR_PLUS))
774 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDR_PLUS) != 0;
775 
776 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_CDRW))
777 		return (priv->caps & BRASERO_DRIVE_CAPS_CDRW) != 0;
778 
779 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW))
780 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDRW) != 0;
781 
782 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED))
783 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDRW) != 0;
784 
785 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS))
786 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDRW_PLUS) != 0;
787 
788 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDR_PLUS_DL))
789 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDR_PLUS_DL) != 0;
790 
791 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS_DL))
792 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDRW_PLUS_DL) != 0;
793 
794 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVD_RAM))
795 		return (priv->caps & BRASERO_DRIVE_CAPS_DVDRAM) != 0;
796 
797 	/* All types of BD-R */
798 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_BD|BRASERO_MEDIUM_WRITABLE))
799 		return (priv->caps & BRASERO_DRIVE_CAPS_BDR) != 0;
800 
801 	if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_BDRE))
802 		return (priv->caps & BRASERO_DRIVE_CAPS_BDRW) != 0;
803 
804 	return FALSE;
805 }
806 
807 /**
808  * brasero_drive_can_write:
809  * @drive: a #BraseroDrive
810  *
811  * Returns whether the disc can burn any disc at all.
812  *
813  * Return value: a #gboolean. TRUE if the drive can write a disc and FALSE otherwise
814  **/
815 gboolean
brasero_drive_can_write(BraseroDrive * drive)816 brasero_drive_can_write (BraseroDrive *drive)
817 {
818 	BraseroDrivePrivate *priv;
819 
820 	g_return_val_if_fail (drive != NULL, FALSE);
821 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
822 
823 	priv = BRASERO_DRIVE_PRIVATE (drive);
824 	return (priv->caps & (BRASERO_DRIVE_CAPS_CDR|
825 			      BRASERO_DRIVE_CAPS_DVDR|
826 			      BRASERO_DRIVE_CAPS_DVDR_PLUS|
827 			      BRASERO_DRIVE_CAPS_CDRW|
828 			      BRASERO_DRIVE_CAPS_DVDRW|
829 			      BRASERO_DRIVE_CAPS_DVDRW_PLUS|
830 			      BRASERO_DRIVE_CAPS_DVDR_PLUS_DL|
831 			      BRASERO_DRIVE_CAPS_DVDRW_PLUS_DL));
832 }
833 
834 static void
brasero_drive_medium_probed(BraseroMedium * medium,BraseroDrive * self)835 brasero_drive_medium_probed (BraseroMedium *medium,
836 			     BraseroDrive *self)
837 {
838 	BraseroDrivePrivate *priv;
839 
840 	priv = BRASERO_DRIVE_PRIVATE (self);
841 
842 	/* only when it is probed */
843 	/* NOTE: BraseroMedium calls GDK_THREADS_ENTER/LEAVE() around g_signal_emit () */
844 	if (brasero_medium_get_status (priv->medium) == BRASERO_MEDIUM_NONE) {
845 		g_object_unref (priv->medium);
846 		priv->medium = NULL;
847 		return;
848 	}
849 
850 	g_signal_emit (self,
851 		       drive_signals [MEDIUM_INSERTED],
852 		       0,
853 		       priv->medium);
854 }
855 
856 /**
857  * This is not public API. Defined in brasero-drive-priv.h.
858  */
859 gboolean
brasero_drive_probing(BraseroDrive * drive)860 brasero_drive_probing (BraseroDrive *drive)
861 {
862 	BraseroDrivePrivate *priv;
863 
864 	g_return_val_if_fail (drive != NULL, FALSE);
865 	g_return_val_if_fail (BRASERO_IS_DRIVE (drive), FALSE);
866 
867 	priv = BRASERO_DRIVE_PRIVATE (drive);
868 	if (priv->probe != NULL)
869 		return TRUE;
870 
871 	if (priv->medium)
872 		return brasero_medium_probing (priv->medium);
873 
874 	return FALSE;
875 }
876 
877 static void
brasero_drive_update_medium(BraseroDrive * drive)878 brasero_drive_update_medium (BraseroDrive *drive)
879 {
880 	BraseroDrivePrivate *priv;
881 
882 	priv = BRASERO_DRIVE_PRIVATE (drive);
883 
884 	if (priv->has_medium) {
885 		if (priv->medium) {
886 			BRASERO_MEDIA_LOG ("Already a medium. Skipping");
887 			return;
888 		}
889 
890 		BRASERO_MEDIA_LOG ("Probing new medium");
891 		priv->medium = g_object_new (BRASERO_TYPE_VOLUME,
892 					     "drive", drive,
893 					     NULL);
894 
895 		g_signal_connect (priv->medium,
896 				  "probed",
897 				  G_CALLBACK (brasero_drive_medium_probed),
898 				  drive);
899 	}
900 	else if (priv->medium) {
901 		BraseroMedium *medium;
902 
903 		BRASERO_MEDIA_LOG ("Medium removed");
904 
905 		medium = priv->medium;
906 		priv->medium = NULL;
907 
908 		g_signal_emit (drive,
909 			       drive_signals [MEDIUM_REMOVED],
910 			       0,
911 			       medium);
912 
913 		g_object_unref (medium);
914 	}
915 }
916 
917 static gboolean
brasero_drive_probed_inside(gpointer data)918 brasero_drive_probed_inside (gpointer data)
919 {
920 	BraseroDrive *self;
921 	BraseroDrivePrivate *priv;
922 
923 	self = BRASERO_DRIVE (data);
924 	priv = BRASERO_DRIVE_PRIVATE (self);
925 
926 	if (!g_mutex_trylock (priv->mutex))
927 		return TRUE;
928 
929 	priv->probe_id = 0;
930 	g_mutex_unlock (priv->mutex);
931 
932 	brasero_drive_update_medium (self);
933 	return FALSE;
934 }
935 
936 static gpointer
brasero_drive_probe_inside_thread(gpointer data)937 brasero_drive_probe_inside_thread (gpointer data)
938 {
939 	gint counter = 0;
940 	GTimeVal wait_time;
941 	const gchar *device;
942 	BraseroScsiErrCode code;
943 	BraseroDrivePrivate *priv;
944 	BraseroDeviceHandle *handle = NULL;
945 	BraseroDrive *drive = BRASERO_DRIVE (data);
946 
947 	priv = BRASERO_DRIVE_PRIVATE (drive);
948 
949 	/* the drive might be busy (a burning is going on) so we don't block
950 	 * but we re-try to open it every second */
951 	device = brasero_drive_get_device (drive);
952 	BRASERO_MEDIA_LOG ("Trying to open device %s", device);
953 
954 	priv->has_medium = FALSE;
955 
956 	handle = brasero_device_handle_open (device, FALSE, &code);
957 	while (!handle && counter <= BRASERO_DRIVE_OPEN_ATTEMPTS) {
958 		sleep (1);
959 
960 		if (priv->probe_cancelled) {
961 			BRASERO_MEDIA_LOG ("Open () cancelled");
962 			goto end;
963 		}
964 
965 		counter ++;
966 		handle = brasero_device_handle_open (device, FALSE, &code);
967 	}
968 
969 	if (!handle) {
970 		BRASERO_MEDIA_LOG ("Open () failed: medium busy");
971 		goto end;
972 	}
973 
974 	if (priv->probe_cancelled) {
975 		BRASERO_MEDIA_LOG ("Open () cancelled");
976 
977 		brasero_device_handle_close (handle);
978 		goto end;
979 	}
980 
981 	while (brasero_spc1_test_unit_ready (handle, &code) != BRASERO_SCSI_OK) {
982 		if (code == BRASERO_SCSI_NO_MEDIUM) {
983 			BRASERO_MEDIA_LOG ("No medium inserted");
984 
985 			brasero_device_handle_close (handle);
986 			goto end;
987 		}
988 
989 		if (code != BRASERO_SCSI_NOT_READY) {
990 			BRASERO_MEDIA_LOG ("Device does not respond");
991 
992 			brasero_device_handle_close (handle);
993 			goto end;
994 		}
995 
996 		g_get_current_time (&wait_time);
997 		g_time_val_add (&wait_time, 2000000);
998 
999 		g_mutex_lock (priv->mutex);
1000 		g_cond_timed_wait (priv->cond_probe,
1001 		                   priv->mutex,
1002 		                   &wait_time);
1003 		g_mutex_unlock (priv->mutex);
1004 
1005 		if (priv->probe_cancelled) {
1006 			BRASERO_MEDIA_LOG ("Device probing cancelled");
1007 
1008 			brasero_device_handle_close (handle);
1009 			goto end;
1010 		}
1011 	}
1012 
1013 	BRASERO_MEDIA_LOG ("Medium inserted");
1014 	brasero_device_handle_close (handle);
1015 
1016 	priv->has_medium = TRUE;
1017 
1018 end:
1019 
1020 	g_mutex_lock (priv->mutex);
1021 
1022 	if (!priv->probe_cancelled)
1023 		priv->probe_id = g_idle_add (brasero_drive_probed_inside, drive);
1024 
1025 	priv->probe = NULL;
1026 	g_cond_broadcast (priv->cond);
1027 	g_mutex_unlock (priv->mutex);
1028 
1029 	g_thread_exit (0);
1030 
1031 	return NULL;
1032 }
1033 
1034 static void
brasero_drive_probe_inside(BraseroDrive * drive)1035 brasero_drive_probe_inside (BraseroDrive *drive)
1036 {
1037 	BraseroDrivePrivate *priv;
1038 
1039 	priv = BRASERO_DRIVE_PRIVATE (drive);
1040 
1041 	if (priv->initial_probe) {
1042 		BRASERO_MEDIA_LOG ("Still initializing the drive properties");
1043 		return;
1044 	}
1045 
1046 	/* Check that a probe is not already being performed */
1047 	if (priv->probe) {
1048 		BRASERO_MEDIA_LOG ("Ongoing probe");
1049 		brasero_drive_cancel_probing (drive);
1050 	}
1051 
1052 	BRASERO_MEDIA_LOG ("Setting new probe");
1053 
1054 	g_mutex_lock (priv->mutex);
1055 
1056 	priv->probe_waiting = FALSE;
1057 	priv->probe_cancelled = FALSE;
1058 
1059 	priv->probe = g_thread_create (brasero_drive_probe_inside_thread,
1060 	                               drive,
1061 				       FALSE,
1062 				       NULL);
1063 
1064 	g_mutex_unlock (priv->mutex);
1065 }
1066 
1067 static void
brasero_drive_medium_gdrive_changed_cb(BraseroDrive * gdrive,BraseroDrive * drive)1068 brasero_drive_medium_gdrive_changed_cb (BraseroDrive *gdrive,
1069 					BraseroDrive *drive)
1070 {
1071 	BraseroDrivePrivate *priv;
1072 
1073 	priv = BRASERO_DRIVE_PRIVATE (drive);
1074 	if (priv->locked || priv->ejecting) {
1075 		BRASERO_MEDIA_LOG ("Waiting for next unlocking of the drive to probe");
1076 
1077 		/* Since the drive was locked, it should
1078 		 * not be possible that the medium
1079 		 * actually changed.
1080 		 * This allows to avoid probing while
1081 		 * we are burning something.
1082 		 * Delay the probe until brasero_drive_unlock ()
1083 		 * is called.  */
1084 		priv->probe_waiting = TRUE;
1085 		return;
1086 	}
1087 
1088 	BRASERO_MEDIA_LOG ("GDrive changed");
1089 	brasero_drive_probe_inside (drive);
1090 }
1091 
1092 static void
brasero_drive_update_gdrive(BraseroDrive * drive,GDrive * gdrive)1093 brasero_drive_update_gdrive (BraseroDrive *drive,
1094                              GDrive *gdrive)
1095 {
1096 	BraseroDrivePrivate *priv;
1097 
1098 	priv = BRASERO_DRIVE_PRIVATE (drive);
1099 	if (priv->gdrive) {
1100 		g_signal_handlers_disconnect_by_func (priv->gdrive,
1101 						      brasero_drive_medium_gdrive_changed_cb,
1102 						      drive);
1103 
1104 		/* Stop any ongoing GIO operation */
1105 		g_cancellable_cancel (priv->cancel);
1106 
1107 		g_object_unref (priv->gdrive);
1108 		priv->gdrive = NULL;
1109 	}
1110 
1111 	BRASERO_MEDIA_LOG ("Setting GDrive %p", gdrive);
1112 
1113 	if (gdrive) {
1114 		priv->gdrive = g_object_ref (gdrive);
1115 
1116 		/* If it's not a fake drive then connect to signal for any
1117 		 * change and check medium inside */
1118 		g_signal_connect (priv->gdrive,
1119 				  "changed",
1120 				  G_CALLBACK (brasero_drive_medium_gdrive_changed_cb),
1121 				  drive);
1122 	}
1123 
1124 	if (priv->locked || priv->ejecting) {
1125 		BRASERO_MEDIA_LOG ("Waiting for next unlocking of the drive to probe");
1126 
1127 		/* Since the drive was locked, it should
1128 		 * not be possible that the medium
1129 		 * actually changed.
1130 		 * This allows to avoid probing while
1131 		 * we are burning something.
1132 		 * Delay the probe until brasero_drive_unlock ()
1133 		 * is called.  */
1134 		priv->probe_waiting = TRUE;
1135 		return;
1136 	}
1137 
1138 	brasero_drive_probe_inside (drive);
1139 }
1140 
1141 /**
1142  * brasero_drive_reprobe:
1143  * @drive: a #BraseroDrive
1144  *
1145  * Reprobes the drive contents. Useful when an operation has just been performed
1146  * (blanking, burning, ...) and medium status should be updated.
1147  *
1148  * NOTE: This operation does not block.
1149  *
1150  **/
1151 
1152 void
brasero_drive_reprobe(BraseroDrive * drive)1153 brasero_drive_reprobe (BraseroDrive *drive)
1154 {
1155 	BraseroDrivePrivate *priv;
1156 	BraseroMedium *medium;
1157 
1158 	g_return_if_fail (drive != NULL);
1159 	g_return_if_fail (BRASERO_IS_DRIVE (drive));
1160 
1161 	priv = BRASERO_DRIVE_PRIVATE (drive);
1162 
1163 	if (priv->gdrive) {
1164 		/* reprobe the contents of the drive system wide */
1165 		g_drive_poll_for_media (priv->gdrive, NULL, NULL, NULL);
1166 	}
1167 
1168 	priv->probe_waiting = FALSE;
1169 
1170 	BRASERO_MEDIA_LOG ("Reprobing inserted medium");
1171 	if (priv->medium) {
1172 		/* remove current medium */
1173 		medium = priv->medium;
1174 		priv->medium = NULL;
1175 
1176 		g_signal_emit (drive,
1177 			       drive_signals [MEDIUM_REMOVED],
1178 			       0,
1179 			       medium);
1180 		g_object_unref (medium);
1181 	}
1182 
1183 	brasero_drive_probe_inside (drive);
1184 }
1185 
1186 static gboolean
brasero_drive_get_caps_profiles(BraseroDrive * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1187 brasero_drive_get_caps_profiles (BraseroDrive *self,
1188                                  BraseroDeviceHandle *handle,
1189                                  BraseroScsiErrCode *code)
1190 {
1191 	BraseroScsiGetConfigHdr *hdr = NULL;
1192 	BraseroScsiProfileDesc *profiles;
1193 	BraseroScsiFeatureDesc *desc;
1194 	BraseroDrivePrivate *priv;
1195 	BraseroScsiResult result;
1196 	int profiles_num;
1197 	int size;
1198 
1199 	priv = BRASERO_DRIVE_PRIVATE (self);
1200 
1201 	BRASERO_MEDIA_LOG ("Checking supported profiles");
1202 	result = brasero_mmc2_get_configuration_feature (handle,
1203 	                                                 BRASERO_SCSI_FEAT_PROFILES,
1204 	                                                 &hdr,
1205 	                                                 &size,
1206 	                                                 code);
1207 	if (result != BRASERO_SCSI_OK) {
1208 		BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
1209 		return FALSE;
1210 	}
1211 
1212 	BRASERO_MEDIA_LOG ("Dectected medium is 0x%x", BRASERO_GET_16 (hdr->current_profile));
1213 
1214 	/* Go through all features available */
1215 	desc = hdr->desc;
1216 	profiles = (BraseroScsiProfileDesc *) desc->data;
1217 	profiles_num = desc->add_len / sizeof (BraseroScsiProfileDesc);
1218 
1219 	while (profiles_num) {
1220 		switch (BRASERO_GET_16 (profiles->number)) {
1221 			case BRASERO_SCSI_PROF_CDR:
1222 				priv->caps |= BRASERO_DRIVE_CAPS_CDR;
1223 				break;
1224 			case BRASERO_SCSI_PROF_CDRW:
1225 				priv->caps |= BRASERO_DRIVE_CAPS_CDRW;
1226 				break;
1227 			case BRASERO_SCSI_PROF_DVD_R:
1228 				priv->caps |= BRASERO_DRIVE_CAPS_DVDR;
1229 				break;
1230 			case BRASERO_SCSI_PROF_DVD_RW_SEQUENTIAL:
1231 			case BRASERO_SCSI_PROF_DVD_RW_RESTRICTED:
1232 				priv->caps |= BRASERO_DRIVE_CAPS_DVDRW;
1233 				break;
1234 			case BRASERO_SCSI_PROF_DVD_RAM:
1235 				priv->caps |= BRASERO_DRIVE_CAPS_DVDRAM;
1236 				break;
1237 			case BRASERO_SCSI_PROF_DVD_R_PLUS_DL:
1238 				priv->caps |= BRASERO_DRIVE_CAPS_DVDR_PLUS_DL;
1239 				break;
1240 			case BRASERO_SCSI_PROF_DVD_RW_PLUS_DL:
1241 				priv->caps |= BRASERO_DRIVE_CAPS_DVDRW_PLUS_DL;
1242 				break;
1243 			case BRASERO_SCSI_PROF_DVD_R_PLUS:
1244 				priv->caps |= BRASERO_DRIVE_CAPS_DVDR_PLUS;
1245 				break;
1246 			case BRASERO_SCSI_PROF_DVD_RW_PLUS:
1247 				priv->caps |= BRASERO_DRIVE_CAPS_DVDRW_PLUS;
1248 				break;
1249 			case BRASERO_SCSI_PROF_BR_R_SEQUENTIAL:
1250 			case BRASERO_SCSI_PROF_BR_R_RANDOM:
1251 				priv->caps |= BRASERO_DRIVE_CAPS_BDR;
1252 				break;
1253 			case BRASERO_SCSI_PROF_BD_RW:
1254 				priv->caps |= BRASERO_DRIVE_CAPS_BDRW;
1255 				break;
1256 			default:
1257 				break;
1258 		}
1259 
1260 		if (priv->initial_probe_cancelled)
1261 			break;
1262 
1263 		/* Move the pointer to the next features */
1264 		profiles ++;
1265 		profiles_num --;
1266 	}
1267 
1268 	g_free (hdr);
1269 	return TRUE;
1270 }
1271 
1272 static void
brasero_drive_get_caps_2A(BraseroDrive * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1273 brasero_drive_get_caps_2A (BraseroDrive *self,
1274                            BraseroDeviceHandle *handle,
1275                            BraseroScsiErrCode *code)
1276 {
1277 	BraseroScsiStatusPage *page_2A = NULL;
1278 	BraseroScsiModeData *data = NULL;
1279 	BraseroDrivePrivate *priv;
1280 	BraseroScsiResult result;
1281 	int size = 0;
1282 
1283 	priv = BRASERO_DRIVE_PRIVATE (self);
1284 
1285 	result = brasero_spc1_mode_sense_get_page (handle,
1286 						   BRASERO_SPC_PAGE_STATUS,
1287 						   &data,
1288 						   &size,
1289 						   code);
1290 	if (result != BRASERO_SCSI_OK) {
1291 		BRASERO_MEDIA_LOG ("MODE SENSE failed");
1292 		return;
1293 	}
1294 
1295 	page_2A = (BraseroScsiStatusPage *) &data->page;
1296 
1297 	if (page_2A->wr_CDR != 0)
1298 		priv->caps |= BRASERO_DRIVE_CAPS_CDR;
1299 	if (page_2A->wr_CDRW != 0)
1300 		priv->caps |= BRASERO_DRIVE_CAPS_CDRW;
1301 	if (page_2A->wr_DVDR != 0)
1302 		priv->caps |= BRASERO_DRIVE_CAPS_DVDR;
1303 	if (page_2A->wr_DVDRAM != 0)
1304 		priv->caps |= BRASERO_DRIVE_CAPS_DVDRAM;
1305 
1306 	g_free (data);
1307 }
1308 
1309 static gpointer
brasero_drive_probe_thread(gpointer data)1310 brasero_drive_probe_thread (gpointer data)
1311 {
1312 	gint counter = 0;
1313 	GTimeVal wait_time;
1314 	const gchar *device;
1315 	BraseroScsiResult res;
1316 	BraseroScsiInquiry hdr;
1317 	BraseroScsiErrCode code;
1318 	BraseroDrivePrivate *priv;
1319 	BraseroDeviceHandle *handle;
1320 	BraseroDrive *drive = BRASERO_DRIVE (data);
1321 
1322 	priv = BRASERO_DRIVE_PRIVATE (drive);
1323 
1324 	/* the drive might be busy (a burning is going on) so we don't block
1325 	 * but we re-try to open it every second */
1326 	device = brasero_drive_get_device (drive);
1327 	BRASERO_MEDIA_LOG ("Trying to open device %s", device);
1328 
1329 	handle = brasero_device_handle_open (device, FALSE, &code);
1330 	while (!handle && counter <= BRASERO_DRIVE_OPEN_ATTEMPTS) {
1331 		sleep (1);
1332 
1333 		if (priv->initial_probe_cancelled) {
1334 			BRASERO_MEDIA_LOG ("Open () cancelled");
1335 			goto end;
1336 		}
1337 
1338 		counter ++;
1339 		handle = brasero_device_handle_open (device, FALSE, &code);
1340 	}
1341 
1342 	if (priv->initial_probe_cancelled) {
1343 		BRASERO_MEDIA_LOG ("Open () cancelled");
1344 		goto end;
1345 	}
1346 
1347 	if (!handle) {
1348 		BRASERO_MEDIA_LOG ("Open () failed: medium busy");
1349 		goto end;
1350 	}
1351 
1352 	while (brasero_spc1_test_unit_ready (handle, &code) != BRASERO_SCSI_OK) {
1353 		if (code == BRASERO_SCSI_NO_MEDIUM) {
1354 			BRASERO_MEDIA_LOG ("No medium inserted");
1355 			goto capabilities;
1356 		}
1357 
1358 		if (code != BRASERO_SCSI_NOT_READY) {
1359 			brasero_device_handle_close (handle);
1360 			BRASERO_MEDIA_LOG ("Device does not respond");
1361 			goto end;
1362 		}
1363 
1364 		g_get_current_time (&wait_time);
1365 		g_time_val_add (&wait_time, 2000000);
1366 
1367 		g_mutex_lock (priv->mutex);
1368 		g_cond_timed_wait (priv->cond_probe,
1369 		                   priv->mutex,
1370 		                   &wait_time);
1371 		g_mutex_unlock (priv->mutex);
1372 
1373 		if (priv->initial_probe_cancelled) {
1374 			brasero_device_handle_close (handle);
1375 			BRASERO_MEDIA_LOG ("Device probing cancelled");
1376 			goto end;
1377 		}
1378 	}
1379 
1380 	BRASERO_MEDIA_LOG ("Device ready");
1381 	priv->has_medium = TRUE;
1382 
1383 capabilities:
1384 
1385 	/* get additional information like the name */
1386 	res = brasero_spc1_inquiry (handle, &hdr, NULL);
1387 	if (res == BRASERO_SCSI_OK) {
1388 		gchar *name_utf8;
1389 		gchar *vendor;
1390 		gchar *model;
1391 		gchar *name;
1392 
1393 		vendor = g_strndup ((gchar *) hdr.vendor, sizeof (hdr.vendor));
1394 		model = g_strndup ((gchar *) hdr.name, sizeof (hdr.name));
1395 		name = g_strdup_printf ("%s %s", g_strstrip (vendor), g_strstrip (model));
1396 		g_free (vendor);
1397 		g_free (model);
1398 
1399 		/* make sure that's proper UTF-8 */
1400 		name_utf8 = g_convert_with_fallback (name,
1401 		                                     -1,
1402 		                                     "ASCII",
1403 		                                     "UTF-8",
1404 		                                     "_",
1405 		                                     NULL,
1406 		                                     NULL,
1407 		                                     NULL);
1408 		g_free (name);
1409 
1410 		priv->name = name_utf8;
1411 	}
1412 
1413 	/* Get supported medium types */
1414 	if (!brasero_drive_get_caps_profiles (drive, handle, &code))
1415 		brasero_drive_get_caps_2A (drive, handle, &code);
1416 
1417 	brasero_device_handle_close (handle);
1418 
1419 	BRASERO_MEDIA_LOG ("Drive caps are %d", priv->caps);
1420 
1421 end:
1422 
1423 	g_mutex_lock (priv->mutex);
1424 
1425 	brasero_drive_update_medium (drive);
1426 
1427 	priv->probe = NULL;
1428 	priv->initial_probe = FALSE;
1429 
1430 	g_cond_broadcast (priv->cond);
1431 	g_mutex_unlock (priv->mutex);
1432 
1433 	g_thread_exit (0);
1434 
1435 	return NULL;
1436 }
1437 
1438 static void
brasero_drive_init_real_device(BraseroDrive * drive,const gchar * device)1439 brasero_drive_init_real_device (BraseroDrive *drive,
1440                                 const gchar *device)
1441 {
1442 	BraseroDrivePrivate *priv;
1443 
1444 	priv = BRASERO_DRIVE_PRIVATE (drive);
1445 
1446 #if defined(HAVE_STRUCT_USCSI_CMD)
1447 	/* On Solaris path points to raw device, block_path points to the block device. */
1448 	g_assert(g_str_has_prefix(device, "/dev/dsk/"));
1449 	priv->device = g_strdup_printf ("/dev/rdsk/%s", device + 9);
1450 	priv->block_device = g_strdup (device);
1451 	BRASERO_MEDIA_LOG ("Initializing block drive %s", priv->block_device);
1452 #else
1453 	priv->device = g_strdup (device);
1454 #endif
1455 
1456 	BRASERO_MEDIA_LOG ("Initializing drive %s from device", priv->device);
1457 
1458 	/* NOTE: why a thread? Because in case of a damaged medium, brasero can
1459 	 * block on some functions until timeout and if we do this in the main
1460 	 * thread then our whole UI blocks. This medium won't be exported by the
1461 	 * BraseroDrive that exported until it returns PROBED signal.
1462 	 * One (good) side effect is that it also improves start time. */
1463 	g_mutex_lock (priv->mutex);
1464 
1465 	priv->initial_probe = TRUE;
1466 	priv->probe = g_thread_create (brasero_drive_probe_thread,
1467 				       drive,
1468 				       FALSE,
1469 				       NULL);
1470 
1471 	g_mutex_unlock (priv->mutex);
1472 }
1473 
1474 static void
brasero_drive_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1475 brasero_drive_set_property (GObject *object,
1476 			    guint prop_id,
1477 			    const GValue *value,
1478 			    GParamSpec *pspec)
1479 {
1480 	BraseroDrivePrivate *priv;
1481 	GDrive *gdrive = NULL;
1482 
1483 	g_return_if_fail (BRASERO_IS_DRIVE (object));
1484 
1485 	priv = BRASERO_DRIVE_PRIVATE (object);
1486 
1487 	switch (prop_id)
1488 	{
1489 	case PROP_UDI:
1490 		break;
1491 	case PROP_GDRIVE:
1492 		if (!priv->device)
1493 			break;
1494 
1495 		gdrive = g_value_get_object (value);
1496 		brasero_drive_update_gdrive (BRASERO_DRIVE (object), gdrive);
1497 		break;
1498 	case PROP_DEVICE:
1499 		/* The first case is only a fake drive/medium */
1500 		if (!g_value_get_string (value))
1501 			priv->medium = g_object_new (BRASERO_TYPE_VOLUME,
1502 						     "drive", object,
1503 						     NULL);
1504 		else
1505 			brasero_drive_init_real_device (BRASERO_DRIVE (object), g_value_get_string (value));
1506 		break;
1507 	default:
1508 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1509 		break;
1510 	}
1511 }
1512 
1513 static void
brasero_drive_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1514 brasero_drive_get_property (GObject *object,
1515 			    guint prop_id,
1516 			    GValue *value,
1517 			    GParamSpec *pspec)
1518 {
1519 	BraseroDrivePrivate *priv;
1520 
1521 	g_return_if_fail (BRASERO_IS_DRIVE (object));
1522 
1523 	priv = BRASERO_DRIVE_PRIVATE (object);
1524 
1525 	switch (prop_id)
1526 	{
1527 	case PROP_UDI:
1528 		break;
1529 	case PROP_GDRIVE:
1530 		g_value_set_object (value, priv->gdrive);
1531 		break;
1532 	case PROP_DEVICE:
1533 		g_value_set_string (value, priv->device);
1534 		break;
1535 	default:
1536 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1537 		break;
1538 	}
1539 }
1540 
1541 static void
brasero_drive_init(BraseroDrive * object)1542 brasero_drive_init (BraseroDrive *object)
1543 {
1544 	BraseroDrivePrivate *priv;
1545 
1546 	priv = BRASERO_DRIVE_PRIVATE (object);
1547 	priv->cancel = g_cancellable_new ();
1548 
1549 	priv->mutex = g_mutex_new ();
1550 	priv->cond = g_cond_new ();
1551 	priv->cond_probe = g_cond_new ();
1552 }
1553 
1554 static void
brasero_drive_finalize(GObject * object)1555 brasero_drive_finalize (GObject *object)
1556 {
1557 	BraseroDrivePrivate *priv;
1558 
1559 	priv = BRASERO_DRIVE_PRIVATE (object);
1560 
1561 	BRASERO_MEDIA_LOG ("Finalizing BraseroDrive");
1562 
1563 	brasero_drive_cancel_probing (BRASERO_DRIVE (object));
1564 
1565 	if (priv->mutex) {
1566 		g_mutex_free (priv->mutex);
1567 		priv->mutex = NULL;
1568 	}
1569 
1570 	if (priv->cond) {
1571 		g_cond_free (priv->cond);
1572 		priv->cond = NULL;
1573 	}
1574 
1575 	if (priv->cond_probe) {
1576 		g_cond_free (priv->cond_probe);
1577 		priv->cond_probe = NULL;
1578 	}
1579 
1580 	if (priv->medium) {
1581 		g_signal_emit (object,
1582 			       drive_signals [MEDIUM_REMOVED],
1583 			       0,
1584 			       priv->medium);
1585 		g_object_unref (priv->medium);
1586 		priv->medium = NULL;
1587 	}
1588 
1589 	if (priv->name) {
1590 		g_free (priv->name);
1591 		priv->name = NULL;
1592 	}
1593 
1594 	if (priv->device) {
1595 		g_free (priv->device);
1596 		priv->device = NULL;
1597 	}
1598 
1599 	if (priv->block_device) {
1600 		g_free (priv->block_device);
1601 		priv->block_device = NULL;
1602 	}
1603 
1604 	if (priv->udi) {
1605 		g_free (priv->udi);
1606 		priv->udi = NULL;
1607 	}
1608 
1609 	if (priv->gdrive) {
1610 		g_signal_handlers_disconnect_by_func (priv->gdrive,
1611 						      brasero_drive_medium_gdrive_changed_cb,
1612 						      object);
1613 		g_object_unref (priv->gdrive);
1614 		priv->gdrive = NULL;
1615 	}
1616 
1617 	if (priv->cancel) {
1618 		g_cancellable_cancel (priv->cancel);
1619 		g_object_unref (priv->cancel);
1620 		priv->cancel = NULL;
1621 	}
1622 
1623 	G_OBJECT_CLASS (brasero_drive_parent_class)->finalize (object);
1624 }
1625 
1626 static void
brasero_drive_class_init(BraseroDriveClass * klass)1627 brasero_drive_class_init (BraseroDriveClass *klass)
1628 {
1629 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
1630 
1631 	g_type_class_add_private (klass, sizeof (BraseroDrivePrivate));
1632 
1633 	object_class->finalize = brasero_drive_finalize;
1634 	object_class->set_property = brasero_drive_set_property;
1635 	object_class->get_property = brasero_drive_get_property;
1636 
1637 	/**
1638  	* BraseroDrive::medium-added:
1639  	* @drive: the object which received the signal
1640   	* @medium: the new medium which was added
1641 	*
1642  	* This signal gets emitted when a new medium was detected
1643  	*
1644  	*/
1645 	drive_signals[MEDIUM_INSERTED] =
1646 		g_signal_new ("medium_added",
1647 		              G_OBJECT_CLASS_TYPE (klass),
1648 		              G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
1649 		              G_STRUCT_OFFSET (BraseroDriveClass, medium_added),
1650 		              NULL, NULL,
1651 		              g_cclosure_marshal_VOID__OBJECT,
1652 		              G_TYPE_NONE, 1,
1653 		              BRASERO_TYPE_MEDIUM);
1654 
1655 	/**
1656  	* BraseroDrive::medium-removed:
1657  	* @drive: the object which received the signal
1658   	* @medium: the medium which was removed
1659 	*
1660  	* This signal gets emitted when a medium is not longer available
1661  	*
1662  	*/
1663 	drive_signals[MEDIUM_REMOVED] =
1664 		g_signal_new ("medium_removed",
1665 		              G_OBJECT_CLASS_TYPE (klass),
1666 		              G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
1667 		              G_STRUCT_OFFSET (BraseroDriveClass, medium_removed),
1668 		              NULL, NULL,
1669 		              g_cclosure_marshal_VOID__OBJECT,
1670 		              G_TYPE_NONE, 1,
1671 		              BRASERO_TYPE_MEDIUM);
1672 
1673 	g_object_class_install_property (object_class,
1674 	                                 PROP_UDI,
1675 	                                 g_param_spec_string("udi",
1676 	                                                     "udi",
1677 	                                                     "HAL udi as a string (Deprecated)",
1678 	                                                     NULL,
1679 	                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1680 	g_object_class_install_property (object_class,
1681 	                                 PROP_GDRIVE,
1682 	                                 g_param_spec_object ("gdrive",
1683 	                                                      "GDrive",
1684 	                                                      "A GDrive object for the drive",
1685 	                                                      G_TYPE_DRIVE,
1686 	                                                     G_PARAM_READWRITE));
1687 	g_object_class_install_property (object_class,
1688 	                                 PROP_DEVICE,
1689 	                                 g_param_spec_string ("device",
1690 	                                                      "Device",
1691 	                                                      "Device path for the drive",
1692 	                                                      NULL,
1693 	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1694 }
1695 
1696