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 <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <unistd.h>
40
41 #include <glib.h>
42 #include <glib/gi18n-lib.h>
43 #include <gdk/gdk.h>
44
45 #include "brasero-media-private.h"
46 #include "brasero-drive-priv.h"
47
48 #include "brasero-medium.h"
49 #include "brasero-drive.h"
50
51 #include "scsi-device.h"
52 #include "scsi-mmc1.h"
53 #include "scsi-mmc2.h"
54 #include "scsi-mmc3.h"
55 #include "scsi-spc1.h"
56 #include "scsi-utils.h"
57 #include "scsi-mode-pages.h"
58 #include "scsi-status-page.h"
59 #include "scsi-write-page.h"
60 #include "scsi-q-subchannel.h"
61 #include "scsi-dvd-structures.h"
62 #include "burn-volume.h"
63
64
65 const gchar *types [] = { N_("File"),
66 N_("CD-ROM"),
67 N_("CD-R"),
68 N_("CD-RW"),
69 N_("DVD-ROM"),
70 N_("DVD-R"),
71 N_("DVD-RW"),
72 N_("DVD+R"),
73 N_("DVD+RW"),
74 N_("DVD+R dual layer"),
75 N_("DVD+RW dual layer"),
76 N_("DVD-R dual layer"),
77 N_("DVD-RAM"),
78 N_("Blu-ray disc"),
79 N_("Writable Blu-ray disc"),
80 N_("Rewritable Blu-ray disc"),
81 NULL };
82
83
84
85 typedef struct _BraseroMediumPrivate BraseroMediumPrivate;
86 struct _BraseroMediumPrivate
87 {
88 GThread *probe;
89 GMutex *mutex;
90 GCond *cond;
91 GCond *cond_probe;
92
93 gint probe_id;
94
95 GSList *tracks;
96
97 const gchar *type;
98
99 gchar *id;
100
101 guint max_rd;
102 guint max_wrt;
103
104 guint *rd_speeds;
105 guint *wr_speeds;
106
107 goffset block_num;
108 goffset block_size;
109
110 guint first_open_track;
111 goffset next_wr_add;
112
113 BraseroMedia info;
114 BraseroDrive *drive;
115
116 gchar *CD_TEXT_title;
117
118 /* Do we really need both? */
119 guint dummy_sao:1;
120 guint dummy_tao:1;
121 guint burnfree:1;
122 guint sao:1;
123 guint tao:1;
124
125 guint blank_command:1;
126 guint write_command:1;
127
128 guint probe_cancelled:1;
129 };
130
131 #define BRASERO_MEDIUM_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_MEDIUM, BraseroMediumPrivate))
132
133 /**
134 * Try to open the drive exclusively but don't block; if drive can't be opened
135 * exclusively then retry every second until we're shut or the drive state
136 * changes to not busy.
137 * No exclusive at the moment since when the medium is mounted we can't use excl
138 */
139
140 #define BUSY_RETRY_TIME 1000
141
142 typedef enum {
143 BRASERO_MEDIUM_TRACK_NONE = 0,
144 BRASERO_MEDIUM_TRACK_DATA = 1,
145 BRASERO_MEDIUM_TRACK_AUDIO = 1 << 1,
146 BRASERO_MEDIUM_TRACK_COPY = 1 << 2,
147 BRASERO_MEDIUM_TRACK_PREEMP = 1 << 3,
148 BRASERO_MEDIUM_TRACK_4_CHANNELS = 1 << 4,
149 BRASERO_MEDIUM_TRACK_INCREMENTAL = 1 << 5,
150 BRASERO_MEDIUM_TRACK_LEADOUT = 1 << 6
151 } BraseroMediumTrackType;
152
153 typedef struct _BraseroMediumTrack BraseroMediumTrack;
154
155 struct _BraseroMediumTrack {
156 guint session;
157 BraseroMediumTrackType type;
158 goffset start;
159 goffset blocks_num;
160 };
161
162 enum
163 {
164 PROP_0,
165 PROP_DRIVE,
166 };
167
168 enum {
169 PROBED,
170 LAST_SIGNAL
171 };
172 static gulong medium_signals [LAST_SIGNAL] = {0, };
173
174 #define BRASERO_MEDIUM_OPEN_ATTEMPTS 5
175
176 static GObjectClass* parent_class = NULL;
177
178
179 /**
180 * brasero_medium_get_tooltip:
181 * @medium: #BraseroMedium
182 *
183 * Returns a tooltip to be displayed in the UI.
184 * It is of the form {content type} {disc type} in {drive name}.
185 *
186 * Return value: a #gchar *.
187 *
188 **/
189 gchar *
brasero_medium_get_tooltip(BraseroMedium * medium)190 brasero_medium_get_tooltip (BraseroMedium *medium)
191 {
192 BraseroDrive *drive;
193 BraseroMedia media;
194 const gchar *type;
195 gchar *label;
196 gchar *name;
197
198 g_return_val_if_fail (medium != NULL, NULL);
199 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), NULL);
200
201 media = brasero_medium_get_status (BRASERO_MEDIUM (medium));
202 if (media & BRASERO_MEDIUM_FILE) {
203 /* Translators: This is a fake drive, a file, and means that
204 * when we're writing, we're writing to a file and create an
205 * image on the hard drive. */
206 return g_strdup (_("Image File"));
207 }
208
209 type = brasero_medium_get_type_string (BRASERO_MEDIUM (medium));
210 drive = brasero_medium_get_drive (BRASERO_MEDIUM (medium));
211 name = brasero_drive_get_display_name (drive);
212
213 if (media & BRASERO_MEDIUM_BLANK) {
214 /* NOTE for translators: the first %s is the disc type and the
215 * second %s the name of the drive this disc is in. */
216 label = g_strdup_printf (_("Blank %s in %s"),
217 type,
218 name);
219 }
220 else if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_HAS_AUDIO|BRASERO_MEDIUM_HAS_DATA)) {
221 /* NOTE for translators: the first %s is the disc type and the
222 * second %s the name of the drive this disc is in. */
223 label = g_strdup_printf (_("Audio and data %s in %s"),
224 type,
225 name);
226 }
227 else if (media & BRASERO_MEDIUM_HAS_AUDIO) {
228 /* NOTE for translators: the first %s is the disc type and the
229 * second %s the name of the drive this disc is in. */
230 label = g_strdup_printf (_("Audio %s in %s"),
231 type,
232 name);
233 }
234 else if (media & BRASERO_MEDIUM_HAS_DATA) {
235 /* NOTE for translators: the first %s is the disc type and the
236 * second %s the name of the drive this disc is in. */
237 label = g_strdup_printf (_("Data %s in %s"),
238 type,
239 name);
240 }
241 else {
242 /* NOTE for translators: the first %s is the disc type and the
243 * second %s the name of the drive this disc is in. */
244 label = g_strdup_printf (_("%s in %s"),
245 type,
246 name);
247 }
248
249 g_free (name);
250 return label;
251 }
252
253 /**
254 * brasero_medium_get_type_string:
255 * @medium: #BraseroMedium
256 *
257 * Returns the medium type as a string to be displayed in a UI.
258 *
259 * Return value: a #gchar *.
260 *
261 **/
262 const gchar *
brasero_medium_get_type_string(BraseroMedium * medium)263 brasero_medium_get_type_string (BraseroMedium *medium)
264 {
265 BraseroMediumPrivate *priv;
266
267 g_return_val_if_fail (medium != NULL, NULL);
268 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), NULL);
269
270 priv = BRASERO_MEDIUM_PRIVATE (medium);
271 return priv->type;
272 }
273
274 /**
275 * brasero_medium_get_status:
276 * @medium: #BraseroMedium
277 *
278 * Gets the medium type and state.
279 *
280 * Return value: a #BraseroMedia.
281 *
282 **/
283 BraseroMedia
brasero_medium_get_status(BraseroMedium * medium)284 brasero_medium_get_status (BraseroMedium *medium)
285 {
286 BraseroMediumPrivate *priv;
287
288 if (!medium)
289 return BRASERO_MEDIUM_NONE;
290
291 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), BRASERO_MEDIUM_NONE);
292
293 priv = BRASERO_MEDIUM_PRIVATE (medium);
294 return priv->info;
295 }
296
297 /**
298 * brasero_medium_get_last_data_track_address:
299 * @medium: #BraseroMedium
300 * @bytes: a #goffset * or NULL
301 * @sectors: a #goffset * or NULL
302 *
303 * Stores in either @bytes (in bytes) or in @sectors (in blocks) the address where
304 * the last session starts. This is useful when creating a multisession image or
305 * when reading the contents of this last track.
306 *
307 * Return value: a #gboolean. Returns TRUE if information could be retrieved.
308 *
309 **/
310 gboolean
brasero_medium_get_last_data_track_address(BraseroMedium * medium,goffset * bytes,goffset * sectors)311 brasero_medium_get_last_data_track_address (BraseroMedium *medium,
312 goffset *bytes,
313 goffset *sectors)
314 {
315 GSList *iter;
316 BraseroMediumPrivate *priv;
317 BraseroMediumTrack *track = NULL;
318
319 g_return_val_if_fail (medium != NULL, FALSE);
320 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
321
322 priv = BRASERO_MEDIUM_PRIVATE (medium);
323
324 for (iter = priv->tracks; iter; iter = iter->next) {
325 BraseroMediumTrack *current;
326
327 current = iter->data;
328 if (current->type & BRASERO_MEDIUM_TRACK_DATA)
329 track = current;
330 }
331
332 if (!track)
333 return FALSE;
334
335 if (bytes)
336 *bytes = track->start * priv->block_size;
337
338 if (sectors)
339 *sectors = track->start;
340
341 return TRUE;
342 }
343
344 /**
345 * brasero_medium_get_last_data_track_space:
346 * @medium: #BraseroMedium
347 * @bytes: a #goffset * or NULL
348 * @sectors: a #goffset * or NULL
349 *
350 * Stores in either @bytes (in bytes) or in @sectors (in blocks) the space used by
351 * the last track on the medium.
352 *
353 * Return value: a #gboolean. Returns TRUE if information could be retrieved.
354 *
355 **/
356 gboolean
brasero_medium_get_last_data_track_space(BraseroMedium * medium,goffset * bytes,goffset * sectors)357 brasero_medium_get_last_data_track_space (BraseroMedium *medium,
358 goffset *bytes,
359 goffset *sectors)
360 {
361 GSList *iter;
362 BraseroMediumPrivate *priv;
363 BraseroMediumTrack *track = NULL;
364
365 g_return_val_if_fail (medium != NULL, FALSE);
366 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
367
368 priv = BRASERO_MEDIUM_PRIVATE (medium);
369
370 for (iter = priv->tracks; iter; iter = iter->next) {
371 BraseroMediumTrack *current;
372
373 current = iter->data;
374 if (current->type & BRASERO_MEDIUM_TRACK_DATA)
375 track = current;
376 }
377
378 if (!track) {
379 if (bytes)
380 *bytes = 0;
381 if (sectors)
382 *sectors = 0;
383 return FALSE;
384 }
385
386 if (bytes)
387 *bytes = track->blocks_num * priv->block_size;
388 if (sectors)
389 *sectors = track->blocks_num;
390
391 return TRUE;
392 }
393
394 /**
395 * brasero_medium_get_track_num:
396 * @medium: #BraseroMedium
397 *
398 * Gets the number of tracks on the medium.
399 *
400 * Return value: a #guint.
401 *
402 **/
403 guint
brasero_medium_get_track_num(BraseroMedium * medium)404 brasero_medium_get_track_num (BraseroMedium *medium)
405 {
406 GSList *iter;
407 guint retval = 0;
408 BraseroMediumPrivate *priv;
409
410 g_return_val_if_fail (medium != NULL, 0);
411 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), 0);
412
413 priv = BRASERO_MEDIUM_PRIVATE (medium);
414 for (iter = priv->tracks; iter; iter = iter->next) {
415 BraseroMediumTrack *current;
416
417 current = iter->data;
418 if (current->type & BRASERO_MEDIUM_TRACK_LEADOUT)
419 break;
420
421 retval ++;
422 }
423
424 return retval;
425 }
426
427 static BraseroMediumTrack *
brasero_medium_get_track(BraseroMedium * medium,guint num)428 brasero_medium_get_track (BraseroMedium *medium,
429 guint num)
430 {
431 guint i = 1;
432 GSList *iter;
433 BraseroMediumPrivate *priv;
434
435 priv = BRASERO_MEDIUM_PRIVATE (medium);
436
437 for (iter = priv->tracks; iter; iter = iter->next) {
438 BraseroMediumTrack *current;
439
440 current = iter->data;
441 if (current->type == BRASERO_MEDIUM_TRACK_LEADOUT)
442 break;
443
444 if (i == num)
445 return current;
446
447 i++;
448 }
449
450 return NULL;
451 }
452
453 /**
454 * brasero_medium_get_track_space:
455 * @medium: a #BraseroMedium
456 * @num: a #guint
457 * @bytes: a #goffset * or NULL
458 * @sectors: a #goffset * or NULL
459 *
460 * Stores in either @bytes (in bytes) or in @sectors (in blocks) the space used
461 * by session @num on the disc.
462 *
463 * Return value: a #gboolean. Returns TRUE if information could be retrieved;
464 * FALSE otherwise (usually when track @num doesn't exist).
465 *
466 **/
467 gboolean
brasero_medium_get_track_space(BraseroMedium * medium,guint num,goffset * bytes,goffset * sectors)468 brasero_medium_get_track_space (BraseroMedium *medium,
469 guint num,
470 goffset *bytes,
471 goffset *sectors)
472 {
473 BraseroMediumPrivate *priv;
474 BraseroMediumTrack *track;
475
476 g_return_val_if_fail (medium != NULL, FALSE);
477 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
478
479 priv = BRASERO_MEDIUM_PRIVATE (medium);
480
481 track = brasero_medium_get_track (medium, num);
482 if (!track) {
483 if (bytes)
484 *bytes = 0;
485 if (sectors)
486 *sectors = 0;
487 return FALSE;
488 }
489
490 if (bytes)
491 *bytes = track->blocks_num * priv->block_size;
492 if (sectors)
493 *sectors = track->blocks_num;
494
495 return TRUE;
496 }
497
498 /**
499 * brasero_medium_get_track_address:
500 * @medium: a #BraseroMedium
501 * @num: a #guint
502 * @bytes: a #goffset * or NULL
503 * @sectors: a #goffset * or NULL
504 *
505 * Stores in either @bytes (in bytes) or in @sectors (in blocks) the address at
506 * which the session identified by @num starts.
507 *
508 * Return value: a #gboolean. Returns TRUE if information could be retrieved;
509 * FALSE otherwise (usually when track @num doesn't exist).
510 *
511 **/
512 gboolean
brasero_medium_get_track_address(BraseroMedium * medium,guint num,goffset * bytes,goffset * sectors)513 brasero_medium_get_track_address (BraseroMedium *medium,
514 guint num,
515 goffset *bytes,
516 goffset *sectors)
517 {
518 BraseroMediumPrivate *priv;
519 BraseroMediumTrack *track;
520
521 g_return_val_if_fail (medium != NULL, FALSE);
522 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
523
524 priv = BRASERO_MEDIUM_PRIVATE (medium);
525
526 track = brasero_medium_get_track (medium, num);
527 if (!track) {
528 if (bytes)
529 *bytes = 0;
530 if (sectors)
531 *sectors = 0;
532 return FALSE;
533 }
534
535 if (bytes)
536 *bytes = track->start * priv->block_size;
537 if (sectors)
538 *sectors = track->start;
539
540 return TRUE;
541 }
542
543 /**
544 * brasero_medium_get_next_writable_address:
545 * @medium: #BraseroMedium
546 *
547 * Gets the address (block number) that can be used to write a new session on @medium
548 *
549 * Return value: a #gint64.
550 *
551 **/
552 gint64
brasero_medium_get_next_writable_address(BraseroMedium * medium)553 brasero_medium_get_next_writable_address (BraseroMedium *medium)
554 {
555 BraseroMediumPrivate *priv;
556
557 g_return_val_if_fail (medium != NULL, 0);
558 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), 0);
559
560 priv = BRASERO_MEDIUM_PRIVATE (medium);
561
562 /* There is one exception to this with closed DVD+RW/DVD-RW restricted */
563 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS)
564 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)
565 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS_DL)) {
566 BraseroMediumTrack *first;
567
568 /* These are always writable so give the next address after the
569 * last volume. */
570 if (!priv->tracks)
571 return 0;
572
573 first = priv->tracks->data;
574
575 /* round to the nearest 16th block */
576 return (((first->start + first->blocks_num) + 15) / 16) * 16;
577 }
578
579 return priv->next_wr_add;
580 }
581
582 /**
583 * brasero_medium_get_max_write_speed:
584 * @medium: #BraseroMedium
585 *
586 * Gets the maximum speed that can be used to write to @medium.
587 * Note: the speed are in B/sec.
588 *
589 * Return value: a #guint64.
590 *
591 **/
592 guint64
brasero_medium_get_max_write_speed(BraseroMedium * medium)593 brasero_medium_get_max_write_speed (BraseroMedium *medium)
594 {
595 BraseroMediumPrivate *priv;
596
597 g_return_val_if_fail (medium != NULL, 0);
598 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), 0);
599
600 priv = BRASERO_MEDIUM_PRIVATE (medium);
601 return priv->max_wrt * 1000;
602 }
603
604 /**
605 * brasero_medium_get_write_speeds:
606 * @medium: #BraseroMedium
607 *
608 * Gets an array holding all possible speeds to write to @medium.
609 * Note: the speed are in B/sec.
610 *
611 * Return value: a #guint64 *.
612 *
613 **/
614 guint64 *
brasero_medium_get_write_speeds(BraseroMedium * medium)615 brasero_medium_get_write_speeds (BraseroMedium *medium)
616 {
617 BraseroMediumPrivate *priv;
618 guint64 *speeds;
619 guint max = 0;
620 guint i;
621
622 g_return_val_if_fail (medium != NULL, NULL);
623 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), NULL);
624
625 priv = BRASERO_MEDIUM_PRIVATE (medium);
626
627 if (!priv->wr_speeds)
628 return NULL;
629
630 while (priv->wr_speeds [max] != 0) max ++;
631
632 speeds = g_new0 (guint64, max + 1);
633
634 /* NOTE: about the following, it's not KiB here but KB */
635 for (i = 0; i < max; i ++)
636 speeds [i] = priv->wr_speeds [i] * 1000;
637
638 return speeds;
639 }
640
641 /**
642 * NOTEs about the following functions:
643 * for all closed media (including ROM types) capacity == size of data and
644 * should be the size of all data on the disc, free space is 0
645 * for all blank -R types capacity == free space and size of data == 0
646 * for all multisession -R types capacity == free space since having the real
647 * capacity of the media would be useless as we can only use this type of media
648 * to append more data
649 * for all -RW types capacity = free space + size of data. Here they can be
650 * appended (use free space) or rewritten (whole capacity).
651 *
652 * Usually:
653 * the free space is the size of the leadout track
654 * the size of data is the sum of track sizes (excluding leadout)
655 * the capacity depends on the media:
656 * for closed discs == sum of track sizes
657 * for multisession discs == free space (leadout size)
658 * for blank discs == (free space) leadout size
659 * for rewritable/blank == use SCSI functions to get capacity (see below)
660 *
661 * In fact we should really need the size of data in DVD+/-RW cases since the
662 * session is always equal to the size of the disc.
663 */
664
665 /**
666 * brasero_medium_get_data_size:
667 * @medium: #BraseroMedium
668 * @bytes: a #gint64 * or NULL
669 * @blocks: a #gint64 * or NULL
670 *
671 * Stores in either @size (in bytes) or @blocks (the number of blocks) the size
672 * used to store data (including audio on CDs) on the disc.
673 *
674 **/
675 void
brasero_medium_get_data_size(BraseroMedium * medium,gint64 * bytes,gint64 * blocks)676 brasero_medium_get_data_size (BraseroMedium *medium,
677 gint64 *bytes,
678 gint64 *blocks)
679 {
680 GSList *iter;
681 BraseroMediumPrivate *priv;
682 BraseroMediumTrack *track = NULL;
683
684 g_return_if_fail (medium != NULL);
685 g_return_if_fail (BRASERO_IS_MEDIUM (medium));
686
687 priv = BRASERO_MEDIUM_PRIVATE (medium);
688
689 if (!priv->tracks) {
690 /* that's probably because it wasn't possible to retrieve info */
691 if (bytes)
692 *bytes = 0;
693
694 if (blocks)
695 *blocks = 0;
696
697 return;
698 }
699
700 for (iter = priv->tracks; iter; iter = iter->next) {
701 BraseroMediumTrack *tmp;
702
703 tmp = iter->data;
704 if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT)
705 break;
706
707 track = iter->data;
708 }
709
710 if (bytes)
711 *bytes = track ? (track->start + track->blocks_num) * priv->block_size: 0;
712
713 if (blocks)
714 *blocks = track ? track->start + track->blocks_num: 0;
715 }
716
717 /**
718 * brasero_medium_get_free_space:
719 * @medium: #BraseroMedium
720 * @bytes: a #gint64 * or NULL
721 * @blocks: a #gint64 * or NULL
722 *
723 * Stores in either @size (in bytes) or @blocks (the number of blocks) the space
724 * on the disc that can be used for writing.
725 *
726 **/
727 void
brasero_medium_get_free_space(BraseroMedium * medium,gint64 * bytes,gint64 * blocks)728 brasero_medium_get_free_space (BraseroMedium *medium,
729 gint64 *bytes,
730 gint64 *blocks)
731 {
732 GSList *iter;
733 BraseroMediumPrivate *priv;
734 BraseroMediumTrack *track = NULL;
735
736 g_return_if_fail (medium != NULL);
737 g_return_if_fail (BRASERO_IS_MEDIUM (medium));
738
739 priv = BRASERO_MEDIUM_PRIVATE (medium);
740
741 if (!priv->tracks) {
742 /* that's probably because it wasn't possible to retrieve info.
743 * maybe it also happens with unformatted DVD+RW */
744
745 if (priv->info & BRASERO_MEDIUM_CLOSED) {
746 if (bytes)
747 *bytes = 0;
748
749 if (blocks)
750 *blocks = 0;
751 }
752 else {
753 if (bytes)
754 *bytes = priv->block_num * priv->block_size;
755
756 if (blocks)
757 *blocks = priv->block_num;
758 }
759
760 return;
761 }
762
763 for (iter = priv->tracks; iter; iter = iter->next) {
764 BraseroMediumTrack *tmp;
765
766 tmp = iter->data;
767 if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT) {
768 track = iter->data;
769 break;
770 }
771 }
772
773 if (bytes) {
774 if (!track) {
775 /* No leadout was found so the disc is probably closed:
776 * no free space left. */
777 *bytes = 0;
778 }
779 else if (track->blocks_num <= 0)
780 *bytes = (priv->block_num - track->start) * priv->block_size;
781 else
782 *bytes = track->blocks_num * priv->block_size;
783 }
784
785 if (blocks) {
786 if (!track) {
787 /* No leadout was found so the disc is probably closed:
788 * no free space left. */
789 *blocks = 0;
790 }
791 else if (track->blocks_num <= 0)
792 *blocks = priv->block_num - track->blocks_num;
793 else
794 *blocks = track->blocks_num;
795 }
796 }
797
798 /**
799 * brasero_medium_get_capacity:
800 * @medium: #BraseroMedium
801 * @bytes: a #gint64 * or NULL
802 * @blocks: a #gint64 * or NULL
803 *
804 * Stores in either @size (in bytes) or @blocks (the number of blocks) the total
805 * disc space.
806 * Note that when the disc is closed this space is the one occupied by data.
807 * Otherwise it is the sum of free and used space.
808 *
809 **/
810 void
brasero_medium_get_capacity(BraseroMedium * medium,gint64 * bytes,gint64 * blocks)811 brasero_medium_get_capacity (BraseroMedium *medium,
812 gint64 *bytes,
813 gint64 *blocks)
814 {
815 BraseroMediumPrivate *priv;
816
817 g_return_if_fail (medium != NULL);
818 g_return_if_fail (BRASERO_IS_MEDIUM (medium));
819
820 priv = BRASERO_MEDIUM_PRIVATE (medium);
821
822 if (priv->info & BRASERO_MEDIUM_REWRITABLE) {
823 if (bytes)
824 *bytes = priv->block_num * priv->block_size;
825
826 if (blocks)
827 *blocks = priv->block_num;
828 }
829 else if (priv->info & BRASERO_MEDIUM_CLOSED)
830 brasero_medium_get_data_size (medium, bytes, blocks);
831 else
832 brasero_medium_get_free_space (medium, bytes, blocks);
833 }
834
835 /**
836 * Test presence of simulate burning/ SAO/ DAO
837 */
838
839 static gboolean
brasero_medium_set_write_mode_page_tao(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)840 brasero_medium_set_write_mode_page_tao (BraseroMedium *self,
841 BraseroDeviceHandle *handle,
842 BraseroScsiErrCode *code)
843 {
844 BraseroScsiModeData *data = NULL;
845 BraseroScsiWritePage *wrt_page;
846 BraseroMediumPrivate *priv;
847 BraseroScsiResult result;
848 int size;
849
850 BRASERO_MEDIA_LOG ("Setting write mode page");
851
852 priv = BRASERO_MEDIUM_PRIVATE (self);
853
854 /* NOTE: this works for CDR, DVDR+-, BDR-SRM */
855 /* make sure the current write mode is TAO. Otherwise the drive will
856 * return the first sector of the pregap instead of the first user
857 * accessible sector. */
858 result = brasero_spc1_mode_sense_get_page (handle,
859 BRASERO_SPC_PAGE_WRITE,
860 &data,
861 &size,
862 code);
863 if (result != BRASERO_SCSI_OK) {
864 BRASERO_MEDIA_LOG ("MODE SENSE failed");
865 /* This isn't necessarily a problem! we better try the rest */
866 return FALSE;
867 }
868
869 wrt_page = (BraseroScsiWritePage *) &data->page;
870
871 BRASERO_MEDIA_LOG ("Former write type %d", wrt_page->write_type);
872 BRASERO_MEDIA_LOG ("Former track mode %d", wrt_page->track_mode);
873 BRASERO_MEDIA_LOG ("Former data block type %d", wrt_page->data_block_type);
874
875 /* "reset some stuff to be on the safe side" (words and ideas
876 * taken from k3b:)). */
877 wrt_page->ps = 0;
878 wrt_page->BUFE = 0;
879 wrt_page->multisession = 0;
880 wrt_page->testwrite = 0;
881 wrt_page->LS_V = 0;
882 wrt_page->copy = 0;
883 wrt_page->FP = 0;
884 wrt_page->session_format = 0;
885 BRASERO_SET_16 (wrt_page->pause_len, 150);
886
887 if (priv->info & BRASERO_MEDIUM_CD) {
888 wrt_page->write_type = BRASERO_SCSI_WRITE_TAO;
889 wrt_page->track_mode = 4;
890 }
891 else if (priv->info & BRASERO_MEDIUM_DVD) {
892 wrt_page->write_type = BRASERO_SCSI_WRITE_PACKET_INC;
893 wrt_page->track_mode = 5;
894 }
895
896 wrt_page->data_block_type = 8;
897
898 result = brasero_spc1_mode_select (handle, data, size, code);
899 g_free (data);
900
901 if (result != BRASERO_SCSI_OK) {
902 BRASERO_MEDIA_LOG ("MODE SELECT failed");
903
904 /* This isn't necessarily a problem! we better try */
905 return FALSE;
906 }
907
908 return TRUE;
909 }
910
911 static gboolean
brasero_medium_test_CD_TAO_simulate(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)912 brasero_medium_test_CD_TAO_simulate (BraseroMedium *self,
913 BraseroDeviceHandle *handle,
914 BraseroScsiErrCode *code)
915 {
916 BraseroScsiGetConfigHdr *hdr = NULL;
917 BraseroScsiCDTAODesc *tao_desc;
918 BraseroScsiFeatureDesc *desc;
919 BraseroMediumPrivate *priv;
920 BraseroScsiResult result;
921 int size;
922
923 priv = BRASERO_MEDIUM_PRIVATE (self);
924
925 /* Try TAO and then SAO if it isn't persistent */
926 BRASERO_MEDIA_LOG ("Checking simulate (CD TAO)");
927 result = brasero_mmc2_get_configuration_feature (handle,
928 BRASERO_SCSI_FEAT_WRT_TAO,
929 &hdr,
930 &size,
931 code);
932 if (result != BRASERO_SCSI_OK) {
933 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
934 return FALSE;
935 }
936
937 desc = hdr->desc;
938 priv->tao = (desc->current != 0);
939 BRASERO_MEDIA_LOG ("TAO feature is %s", priv->tao? "supported":"not supported");
940
941 tao_desc = (BraseroScsiCDTAODesc *) desc->data;
942 priv->dummy_tao = tao_desc->dummy != 0;
943 priv->burnfree = tao_desc->buf != 0;
944
945 /* See if CD-RW is supported which means in
946 * this case that we can blank */
947 priv->blank_command = (tao_desc->CDRW != 0);
948 BRASERO_MEDIA_LOG ("Medium %s be blanked", priv->blank_command? "can":"cannot");
949
950 g_free (hdr);
951 return TRUE;
952 }
953
954 static gboolean
brasero_medium_test_CD_SAO_simulate(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)955 brasero_medium_test_CD_SAO_simulate (BraseroMedium *self,
956 BraseroDeviceHandle *handle,
957 BraseroScsiErrCode *code)
958 {
959 BraseroScsiGetConfigHdr *hdr = NULL;
960 BraseroScsiCDSAODesc *sao_desc;
961 BraseroScsiFeatureDesc *desc;
962 BraseroMediumPrivate *priv;
963 BraseroScsiResult result;
964 int size;
965
966 priv = BRASERO_MEDIUM_PRIVATE (self);
967
968 BRASERO_MEDIA_LOG ("Checking simulate (CD SAO)");
969 result = brasero_mmc2_get_configuration_feature (handle,
970 BRASERO_SCSI_FEAT_WRT_SAO_RAW,
971 &hdr,
972 &size,
973 code);
974 if (result != BRASERO_SCSI_OK) {
975 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
976 return FALSE;
977 }
978
979 desc = hdr->desc;
980 priv->sao = (desc->current != 0);
981 BRASERO_MEDIA_LOG ("SAO feature is %s", priv->sao? "supported":"not supported");
982
983 sao_desc = (BraseroScsiCDSAODesc *) desc->data;
984 priv->dummy_sao = sao_desc->dummy != 0;
985 priv->burnfree = sao_desc->buf != 0;
986
987 g_free (hdr);
988 return TRUE;
989 }
990
991 static gboolean
brasero_medium_test_DVDRW_incremental_simulate(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)992 brasero_medium_test_DVDRW_incremental_simulate (BraseroMedium *self,
993 BraseroDeviceHandle *handle,
994 BraseroScsiErrCode *code)
995 {
996 BraseroScsiDVDRWlessWrtDesc *less_wrt_desc;
997 BraseroScsiGetConfigHdr *hdr = NULL;
998 BraseroScsiFeatureDesc *desc;
999 BraseroMediumPrivate *priv;
1000 BraseroScsiResult result;
1001 int size;
1002
1003 priv = BRASERO_MEDIUM_PRIVATE (self);
1004
1005 /* Try incremental feature */
1006 BRASERO_MEDIA_LOG ("Checking incremental and simulate feature");
1007 result = brasero_mmc2_get_configuration_feature (handle,
1008 BRASERO_SCSI_FEAT_WRT_INCREMENT,
1009 &hdr,
1010 &size,
1011 code);
1012 if (result != BRASERO_SCSI_OK) {
1013 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
1014 return FALSE;
1015 }
1016
1017 priv->tao = (hdr->desc->current != 0);
1018 g_free (hdr);
1019 hdr = NULL;
1020
1021 BRASERO_MEDIA_LOG ("Incremental feature is %s", priv->tao? "supported":"not supported");
1022
1023 /* Only DVD-R(W) support simulation */
1024 BRASERO_MEDIA_LOG ("Checking (DVD-R(W) simulate)");
1025 result = brasero_mmc2_get_configuration_feature (handle,
1026 BRASERO_SCSI_FEAT_WRT_DVD_LESS,
1027 &hdr,
1028 &size,
1029 code);
1030 if (result != BRASERO_SCSI_OK) {
1031 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
1032 return FALSE;
1033 }
1034
1035 desc = hdr->desc;
1036
1037 /* NOTE: SAO feature is always supported if this feature is current
1038 * See MMC5 5.3.25 Write feature parameters */
1039 priv->sao = (desc->current != 0);
1040 BRASERO_MEDIA_LOG ("SAO feature is %s", priv->sao? "supported":"not supported");
1041
1042 less_wrt_desc = (BraseroScsiDVDRWlessWrtDesc *) desc->data;
1043 priv->dummy_sao = less_wrt_desc->dummy != 0;
1044 priv->dummy_tao = less_wrt_desc->dummy != 0;
1045 priv->burnfree = less_wrt_desc->buf != 0;
1046
1047 /* NOTE: it's said that this is only valid when the current
1048 * bit is set which is always the case in this function */
1049 priv->blank_command = (less_wrt_desc->rw_DVD != 0);
1050 BRASERO_MEDIA_LOG ("Medium %s be blanked", priv->blank_command? "can":"cannot");
1051
1052 g_free (hdr);
1053 return TRUE;
1054 }
1055
1056 /**
1057 * This is a last resort when the initialization has failed.
1058 */
1059
1060 static void
brasero_medium_test_2A_simulate(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1061 brasero_medium_test_2A_simulate (BraseroMedium *self,
1062 BraseroDeviceHandle *handle,
1063 BraseroScsiErrCode *code)
1064 {
1065 BraseroScsiStatusPage *page_2A = NULL;
1066 BraseroScsiModeData *data = NULL;
1067 BraseroMediumPrivate *priv;
1068 BraseroScsiResult result;
1069 int size = 0;
1070
1071 priv = BRASERO_MEDIUM_PRIVATE (self);
1072
1073 /* FIXME: we need to get a way to get the write types */
1074 result = brasero_spc1_mode_sense_get_page (handle,
1075 BRASERO_SPC_PAGE_STATUS,
1076 &data,
1077 &size,
1078 code);
1079 if (result != BRASERO_SCSI_OK) {
1080 BRASERO_MEDIA_LOG ("MODE SENSE failed");
1081 return;
1082 }
1083
1084 /* NOTE: this bit is only valid:
1085 * - for CDs when mode write is TAO or SAO
1086 * - for DVDs when mode write is incremental or SAO */
1087
1088 page_2A = (BraseroScsiStatusPage *) &data->page;
1089 priv->dummy_sao = page_2A->dummy != 0;
1090 priv->dummy_tao = page_2A->dummy != 0;
1091 priv->burnfree = page_2A->buffer != 0;
1092
1093 priv->blank_command = (page_2A->wr_CDRW != 0);
1094 BRASERO_MEDIA_LOG ("Medium %s be blanked", priv->blank_command? "can":"cannot");
1095
1096 g_free (data);
1097 }
1098
1099 static void
brasero_medium_init_caps(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1100 brasero_medium_init_caps (BraseroMedium *self,
1101 BraseroDeviceHandle *handle,
1102 BraseroScsiErrCode *code)
1103 {
1104 BraseroMediumPrivate *priv;
1105 BraseroScsiResult res;
1106
1107 priv = BRASERO_MEDIUM_PRIVATE (self);
1108
1109 /* These special media don't support/need burnfree, simulation, tao/sao */
1110 if (priv->info & (BRASERO_MEDIUM_PLUS|BRASERO_MEDIUM_BD))
1111 return;
1112
1113 if (priv->info & BRASERO_MEDIUM_CD) {
1114 /* we have to do both */
1115 res = brasero_medium_test_CD_SAO_simulate (self, handle, code);
1116 if (res)
1117 brasero_medium_test_CD_TAO_simulate (self, handle, code);
1118 }
1119 else
1120 res = brasero_medium_test_DVDRW_incremental_simulate (self, handle, code);
1121
1122 BRASERO_MEDIA_LOG ("Tested simulation %d %d, burnfree %d",
1123 priv->dummy_tao,
1124 priv->dummy_sao,
1125 priv->burnfree);
1126
1127 if (res)
1128 return;
1129
1130 /* it didn't work out as expected use fallback */
1131 BRASERO_MEDIA_LOG ("Using fallback 2A page for testing simulation and burnfree");
1132 brasero_medium_test_2A_simulate (self, handle, code);
1133
1134 BRASERO_MEDIA_LOG ("Re-tested simulation %d %d, burnfree %d",
1135 priv->dummy_tao,
1136 priv->dummy_sao,
1137 priv->burnfree);
1138 }
1139
1140 /**
1141 * Function to retrieve the capacity of a media
1142 */
1143
1144 static gboolean
brasero_medium_get_capacity_CD_RW(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1145 brasero_medium_get_capacity_CD_RW (BraseroMedium *self,
1146 BraseroDeviceHandle *handle,
1147 BraseroScsiErrCode *code)
1148 {
1149 BraseroScsiAtipData *atip_data = NULL;
1150 BraseroMediumPrivate *priv;
1151 BraseroScsiResult result;
1152 int size = 0;
1153
1154 priv = BRASERO_MEDIUM_PRIVATE (self);
1155
1156 BRASERO_MEDIA_LOG ("Retrieving capacity from atip");
1157
1158 result = brasero_mmc1_read_atip (handle,
1159 &atip_data,
1160 &size,
1161 NULL);
1162
1163 if (result != BRASERO_SCSI_OK) {
1164 BRASERO_MEDIA_LOG ("READ ATIP failed (scsi error)");
1165 return FALSE;
1166 }
1167
1168 /* check the size of the structure: it must be at least 16 bytes long */
1169 if (size < 16) {
1170 if (size)
1171 g_free (atip_data);
1172
1173 BRASERO_MEDIA_LOG ("READ ATIP failed (wrong size)");
1174 return FALSE;
1175 }
1176
1177 priv->block_num = BRASERO_MSF_TO_LBA (atip_data->desc->leadout_mn,
1178 atip_data->desc->leadout_sec,
1179 atip_data->desc->leadout_frame);
1180 g_free (atip_data);
1181
1182 BRASERO_MEDIA_LOG ("Format capacity %lli %lli",
1183 priv->block_num,
1184 priv->block_size);
1185
1186 return TRUE;
1187 }
1188
1189 static gboolean
brasero_medium_get_capacity_DVD_RW(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1190 brasero_medium_get_capacity_DVD_RW (BraseroMedium *self,
1191 BraseroDeviceHandle *handle,
1192 BraseroScsiErrCode *code)
1193 {
1194 BraseroScsiFormatCapacitiesHdr *hdr = NULL;
1195 BraseroScsiFormattableCapacityDesc *desc;
1196 BraseroScsiMaxCapacityDesc *current;
1197 BraseroMediumPrivate *priv;
1198 BraseroScsiResult result;
1199 gint i, max;
1200 gint size;
1201
1202 BRASERO_MEDIA_LOG ("Retrieving format capacity");
1203
1204 priv = BRASERO_MEDIUM_PRIVATE (self);
1205 result = brasero_mmc2_read_format_capacities (handle,
1206 &hdr,
1207 &size,
1208 code);
1209 if (result != BRASERO_SCSI_OK) {
1210 BRASERO_MEDIA_LOG ("READ FORMAT CAPACITIES failed");
1211 return FALSE;
1212 }
1213
1214 /* NOTE: for BD-RE there is a slight problem to determine the exact
1215 * capacity of the medium when it is unformatted. Indeed the final size
1216 * of the User Data Area will depend on the size of the Spare areas.
1217 * On the other hand if it's formatted then that's OK, just take the
1218 * current one.
1219 * NOTE: that could work also for BD-R SRM+POW and BD-R RRM */
1220
1221 /* see if the media is already formatted */
1222 current = hdr->max_caps;
1223 if (!(current->type & BRASERO_SCSI_DESC_FORMATTED)) {
1224 BRASERO_MEDIA_LOG ("Unformatted media");
1225 /* If it's sequential, it's not unformatted */
1226 if (!(priv->info & BRASERO_MEDIUM_SEQUENTIAL))
1227 priv->info |= BRASERO_MEDIUM_UNFORMATTED;
1228
1229 /* if unformatted, a DVD-RAM will return its maximum formattable
1230 * size in this descriptor and that's what we're looking for. */
1231 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVD_RAM)) {
1232 priv->block_num = BRASERO_GET_32 (current->blocks_num);
1233 priv->block_size = 2048;
1234 goto end;
1235 }
1236 }
1237 else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BDRE)) {
1238 priv->block_num = BRASERO_GET_32 (current->blocks_num);
1239 priv->block_size = 2048;
1240 goto end;
1241 }
1242
1243 max = (hdr->len -
1244 sizeof (BraseroScsiMaxCapacityDesc)) /
1245 sizeof (BraseroScsiFormattableCapacityDesc);
1246
1247 desc = hdr->desc;
1248 for (i = 0; i < max; i ++, desc ++) {
1249 /* search for the correct descriptor */
1250 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS)) {
1251 if (desc->format_type == BRASERO_SCSI_DVDRW_PLUS) {
1252 priv->block_num = BRASERO_GET_32 (desc->blocks_num);
1253 priv->block_size = BRASERO_GET_24 (desc->type_param);
1254
1255 /* that can happen */
1256 if (!priv->block_size)
1257 priv->block_size = 2048;
1258
1259 break;
1260 }
1261 }
1262 else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BDRE)) {
1263 /* This is for unformatted BDRE: since we can't know the
1264 * size of the Spare Area in advance, we take the vendor
1265 * preferred one. Always following are the smallest one
1266 * and the biggest one. */
1267 if (desc->format_type == BRASERO_SCSI_BDRE_FORMAT) {
1268 priv->block_num = BRASERO_GET_32 (desc->blocks_num);
1269 break;
1270 }
1271 }
1272 else if (desc->format_type == BRASERO_SCSI_MAX_PACKET_SIZE_FORMAT) {
1273 priv->block_num = BRASERO_GET_32 (desc->blocks_num);
1274 break;
1275 }
1276 }
1277
1278 end:
1279
1280 BRASERO_MEDIA_LOG ("Format capacity %lli %lli",
1281 priv->block_num,
1282 priv->block_size);
1283
1284 g_free (hdr);
1285 return TRUE;
1286 }
1287
1288 static gboolean
brasero_medium_get_capacity_by_type(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1289 brasero_medium_get_capacity_by_type (BraseroMedium *self,
1290 BraseroDeviceHandle *handle,
1291 BraseroScsiErrCode *code)
1292 {
1293 BraseroMediumPrivate *priv;
1294
1295 priv = BRASERO_MEDIUM_PRIVATE (self);
1296
1297 /* For DVDs/BDs that's always that block size */
1298 priv->block_size = 2048;
1299
1300 if (!(priv->info & BRASERO_MEDIUM_REWRITABLE))
1301 return TRUE;
1302
1303 if (priv->info & BRASERO_MEDIUM_CD)
1304 brasero_medium_get_capacity_CD_RW (self, handle, code);
1305 else /* Works for BD-RE as well */
1306 brasero_medium_get_capacity_DVD_RW (self, handle, code);
1307
1308 return TRUE;
1309 }
1310
1311 /**
1312 * Functions to retrieve the speed
1313 */
1314
1315 static gboolean
brasero_medium_get_speed_mmc3(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1316 brasero_medium_get_speed_mmc3 (BraseroMedium *self,
1317 BraseroDeviceHandle *handle,
1318 BraseroScsiErrCode *code)
1319 {
1320 int size = 0;
1321 int num_desc, i;
1322 gint max_rd, max_wrt;
1323 BraseroScsiResult result;
1324 BraseroMediumPrivate *priv;
1325 BraseroScsiWrtSpdDesc *desc;
1326 BraseroScsiGetPerfData *wrt_perf = NULL;
1327
1328 BRASERO_MEDIA_LOG ("Retrieving speed (Get Performance)");
1329
1330 /* NOTE: this only work if there is RT streaming feature with
1331 * wspd bit set to 1. At least an MMC3 drive. */
1332 priv = BRASERO_MEDIUM_PRIVATE (self);
1333 result = brasero_mmc3_get_performance_wrt_spd_desc (handle,
1334 &wrt_perf,
1335 &size,
1336 code);
1337
1338 if (result != BRASERO_SCSI_OK) {
1339 BRASERO_MEDIA_LOG ("GET PERFORMANCE failed");
1340 return FALSE;
1341 }
1342
1343 BRASERO_MEDIA_LOG ("Successfully retrieved a header: size %d, address %p", size, wrt_perf);
1344
1345 /* Choose the smallest value for size */
1346 size = MIN (size, BRASERO_GET_32 (wrt_perf->hdr.len) + sizeof (wrt_perf->hdr.len));
1347 BRASERO_MEDIA_LOG ("Updated header size = %d", size);
1348
1349 /* NOTE: I don't know why but on some architecture/with some compilers
1350 * when size < sizeof (BraseroScsiGetPerfHdr) the whole operation below
1351 * is treated as signed which leads to have an outstanding number of
1352 * descriptors instead of a negative one. So be anal when checking. */
1353 if (size <= (sizeof (BraseroScsiGetPerfHdr) + sizeof (BraseroScsiWrtSpdDesc))) {
1354 BRASERO_MEDIA_LOG ("No descriptors");
1355 goto end;
1356 }
1357
1358 /* Calculate the number of descriptors */
1359 num_desc = (size - sizeof (BraseroScsiGetPerfHdr)) / sizeof (BraseroScsiWrtSpdDesc);
1360 BRASERO_MEDIA_LOG ("Got %d descriptor(s)", num_desc);
1361
1362 if (num_desc <= 0)
1363 goto end;
1364
1365 priv->rd_speeds = g_new0 (guint, num_desc + 1);
1366 priv->wr_speeds = g_new0 (guint, num_desc + 1);
1367
1368 max_rd = 0;
1369 max_wrt = 0;
1370
1371 desc = (BraseroScsiWrtSpdDesc*) &wrt_perf->data;
1372
1373 for (i = 0; i < num_desc; i ++) {
1374 BRASERO_MEDIA_LOG ("Descriptor n° %d, address = %p", i, (desc + i));
1375
1376 priv->rd_speeds [i] = BRASERO_GET_32 (desc [i].rd_speed);
1377 priv->wr_speeds [i] = BRASERO_GET_32 (desc [i].wr_speed);
1378
1379 BRASERO_MEDIA_LOG ("RD = %u / WRT = %u",
1380 priv->rd_speeds [i],
1381 priv->wr_speeds [i]);
1382
1383 max_rd = MAX (max_rd, priv->rd_speeds [i]);
1384 max_wrt = MAX (max_wrt, priv->wr_speeds [i]);
1385 }
1386
1387 priv->max_rd = max_rd;
1388 priv->max_wrt = max_wrt;
1389
1390 BRASERO_MEDIA_LOG ("Maximum Speed (mmc3) %i", max_wrt);
1391
1392 end:
1393
1394 g_free (wrt_perf);
1395
1396 /* strangely there are so drives (I know one case) which support this
1397 * function but don't report any speed. So if our top speed is 0 then
1398 * use the other way to get the speed. It was a Teac */
1399 if (!priv->max_wrt)
1400 return FALSE;
1401
1402 return TRUE;
1403 }
1404
1405 static gboolean
brasero_medium_get_page_2A_write_speed_desc(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1406 brasero_medium_get_page_2A_write_speed_desc (BraseroMedium *self,
1407 BraseroDeviceHandle *handle,
1408 BraseroScsiErrCode *code)
1409 {
1410 BraseroScsiStatusPage *page_2A = NULL;
1411 BraseroScsiStatusWrSpdDesc *desc;
1412 BraseroScsiModeData *data = NULL;
1413 BraseroMediumPrivate *priv;
1414 BraseroScsiResult result;
1415 gint desc_num, i;
1416 gint max_wrt = 0;
1417 gint max_num;
1418 int size = 0;
1419
1420 BRASERO_MEDIA_LOG ("Retrieving speed (2A speeds)");
1421
1422 priv = BRASERO_MEDIUM_PRIVATE (self);
1423 result = brasero_spc1_mode_sense_get_page (handle,
1424 BRASERO_SPC_PAGE_STATUS,
1425 &data,
1426 &size,
1427 code);
1428 if (result != BRASERO_SCSI_OK) {
1429 BRASERO_MEDIA_LOG ("MODE SENSE failed");
1430 return FALSE;
1431 }
1432
1433 page_2A = (BraseroScsiStatusPage *) &data->page;
1434
1435 /* Reminder: size = sizeof (BraseroScsiStatusPage) + sizeof (BraseroScsiModeHdr) */
1436 size = MIN (size, sizeof (data->hdr.len) + BRASERO_GET_16 (data->hdr.len));
1437
1438 if (size < (G_STRUCT_OFFSET (BraseroScsiStatusPage, copy_mngt_rev) + sizeof (BraseroScsiModeHdr))) {
1439 g_free (data);
1440 BRASERO_MEDIA_LOG ("wrong page size");
1441 return FALSE;
1442 }
1443
1444 priv->max_rd = BRASERO_GET_16 (page_2A->rd_max_speed);
1445 priv->max_wrt = BRASERO_GET_16 (page_2A->wr_max_speed);
1446
1447 /* Check if we can use the speed descriptors. There must be at least one
1448 * available; if not use maximum speed member. */
1449 if (size < (G_STRUCT_OFFSET (BraseroScsiStatusPage, wr_spd_desc) +
1450 sizeof (BraseroScsiModeHdr) +
1451 sizeof (BraseroScsiWrtSpdDesc))) {
1452 BRASERO_MEDIA_LOG ("Maximum Speed (Page 2A [old]) %i", priv->max_wrt);
1453
1454 /* also add fake speed descriptors */
1455 priv->wr_speeds = g_new0 (guint, 2);
1456 priv->wr_speeds [0] = BRASERO_GET_16 (page_2A->wr_max_speed);
1457 priv->rd_speeds = g_new0 (guint, 2);
1458 priv->rd_speeds [0] = BRASERO_GET_16 (page_2A->rd_max_speed);
1459
1460 g_free (data);
1461 return TRUE;
1462 }
1463
1464 desc_num = BRASERO_GET_16 (page_2A->wr_speed_desc_num);
1465 max_num = size -
1466 sizeof (BraseroScsiStatusPage) -
1467 sizeof (BraseroScsiModeHdr);
1468 max_num /= sizeof (BraseroScsiWrtSpdDesc);
1469
1470 if (max_num < 0)
1471 max_num = 0;
1472
1473 if (desc_num > max_num)
1474 desc_num = max_num;
1475
1476 priv->wr_speeds = g_new0 (guint, desc_num + 1);
1477
1478 desc = page_2A->wr_spd_desc;
1479 for (i = 0; i < desc_num; i ++) {
1480 /* It happens (I have such a drive) that it returns descriptors
1481 * with the same speeds each (in this case the maximum) */
1482 if (i > 0 && priv->wr_speeds [i-1] == BRASERO_GET_16 (desc [i].speed))
1483 continue;
1484
1485 priv->wr_speeds [i] = BRASERO_GET_16 (desc [i].speed);
1486 max_wrt = MAX (max_wrt, priv->wr_speeds [i]);
1487 }
1488
1489 if (max_wrt)
1490 priv->max_wrt = max_wrt;
1491
1492 BRASERO_MEDIA_LOG ("Maximum Speed (Page 2A) %i", priv->max_wrt);
1493 g_free (data);
1494
1495 return TRUE;
1496 }
1497
1498 static gboolean
brasero_medium_get_speed(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1499 brasero_medium_get_speed (BraseroMedium *self,
1500 BraseroDeviceHandle *handle,
1501 BraseroScsiErrCode *code)
1502 {
1503 BraseroScsiResult result;
1504
1505 BRASERO_MEDIA_LOG ("Retrieving media available speeds");
1506
1507 result = brasero_medium_get_speed_mmc3 (self, handle, code);
1508 if (result == TRUE)
1509 return result;
1510
1511 /* Fallback */
1512 result = brasero_medium_get_page_2A_write_speed_desc (self, handle, code);
1513 return result;
1514 }
1515
1516 /**
1517 * Functions to get information about disc contents
1518 */
1519
1520 static gboolean
brasero_medium_track_volume_size(BraseroMedium * self,BraseroMediumTrack * track,BraseroDeviceHandle * handle)1521 brasero_medium_track_volume_size (BraseroMedium *self,
1522 BraseroMediumTrack *track,
1523 BraseroDeviceHandle *handle)
1524 {
1525 GError *error = NULL;
1526 BraseroVolSrc *vol;
1527 gint64 nb_blocks;
1528 gboolean res;
1529
1530 if (!track)
1531 return FALSE;
1532
1533 /* This is a special case. For DVD+RW and DVD-RW in restricted
1534 * mode, there is only one session that takes the whole disc size
1535 * once formatted. That doesn't necessarily means they have data
1536 * Note also that they are reported as complete though you can
1537 * still add data (with growisofs). It is nevertheless on the
1538 * condition that the fs is valid.
1539 * So we check if their first and only volume is valid.
1540 * That's also used when the track size is reported 300 KiB
1541 * see below */
1542 vol = brasero_volume_source_open_device_handle (handle, NULL);
1543 res = brasero_volume_get_size (vol,
1544 track->start,
1545 &nb_blocks,
1546 &error);
1547 brasero_volume_source_close (vol);
1548
1549 if (!res) {
1550 BRASERO_MEDIA_LOG ("Failed to retrieve the volume size: %s",
1551 error && error->message ?
1552 error->message:"unknown error");
1553
1554 if (error)
1555 g_error_free (error);
1556
1557 return FALSE;
1558 }
1559
1560 track->blocks_num = nb_blocks;
1561 return TRUE;
1562 }
1563
1564 static gboolean
brasero_medium_track_written_SAO(BraseroDeviceHandle * handle,int track_num,int track_start)1565 brasero_medium_track_written_SAO (BraseroDeviceHandle *handle,
1566 int track_num,
1567 int track_start)
1568 {
1569 BraseroScsiErrCode error = BRASERO_SCSI_ERROR_NONE;
1570 unsigned char buffer [2048];
1571 BraseroScsiResult result;
1572
1573 BRASERO_MEDIA_LOG ("Checking for TDBs in track pregap.");
1574
1575 /* To avoid blocking try to check whether it is readable */
1576 result = brasero_mmc1_read_block (handle,
1577 TRUE,
1578 BRASERO_SCSI_BLOCK_TYPE_ANY,
1579 BRASERO_SCSI_BLOCK_HEADER_NONE,
1580 BRASERO_SCSI_BLOCK_NO_SUBCHANNEL,
1581 track_start - 1,
1582 1,
1583 NULL,
1584 0,
1585 &error);
1586 if (result != BRASERO_SCSI_OK || error != BRASERO_SCSI_ERROR_NONE)
1587 return TRUE;
1588
1589 result = brasero_mmc1_read_block (handle,
1590 TRUE,
1591 BRASERO_SCSI_BLOCK_TYPE_ANY,
1592 BRASERO_SCSI_BLOCK_HEADER_NONE,
1593 BRASERO_SCSI_BLOCK_NO_SUBCHANNEL,
1594 track_start - 1,
1595 1,
1596 buffer,
1597 sizeof (buffer),
1598 &error);
1599 if (result == BRASERO_SCSI_OK && error == BRASERO_SCSI_ERROR_NONE) {
1600 int i;
1601
1602 if (buffer [0] != 'T' || buffer [1] != 'D' || buffer [2] != 'I') {
1603 BRASERO_MEDIA_LOG ("Track was probably recorded in SAO mode - no TDB.");
1604 return TRUE;
1605 }
1606
1607 /* Find the TDU (16 bytes) for the track (there can be for other tracks).
1608 * i must be < 128 = ((2048 - 8 (size TDB)) / 16 (size TDU). */
1609 for (i = 0; i < 128; i ++) {
1610 if (BRASERO_GET_BCD (buffer [8 + i * 16]) != track_num)
1611 break;
1612 }
1613
1614 if (i >= 128) {
1615 BRASERO_MEDIA_LOG ("No appropriate TDU for track");
1616 return TRUE;
1617 }
1618
1619 if (buffer [8 + i * 16] == 0x80 || buffer [8 + i * 16] == 0x00) {
1620 BRASERO_MEDIA_LOG ("Track was recorded in TAO mode.");
1621 return FALSE;
1622 }
1623
1624 BRASERO_MEDIA_LOG ("Track was recorded in Packet mode.");
1625 return FALSE;
1626 }
1627
1628 BRASERO_MEDIA_LOG ("No pregap. That track must have been recorded in SAO mode.");
1629 return TRUE;
1630 }
1631
1632 static gboolean
brasero_medium_track_get_info(BraseroMedium * self,gboolean multisession,BraseroMediumTrack * track,int track_num,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)1633 brasero_medium_track_get_info (BraseroMedium *self,
1634 gboolean multisession,
1635 BraseroMediumTrack *track,
1636 int track_num,
1637 BraseroDeviceHandle *handle,
1638 BraseroScsiErrCode *code)
1639 {
1640 BraseroScsiTrackInfo track_info;
1641 BraseroMediumPrivate *priv;
1642 BraseroScsiResult result;
1643 int size;
1644
1645 BRASERO_MEDIA_LOG ("Retrieving track information for %i", track_num);
1646
1647 priv = BRASERO_MEDIUM_PRIVATE (self);
1648
1649 /* at this point we know the type of the disc that's why we set the
1650 * size according to this type. That may help to avoid outrange address
1651 * errors. */
1652 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DUAL_L|BRASERO_MEDIUM_WRITABLE))
1653 size = 48;
1654 else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_PLUS|BRASERO_MEDIUM_WRITABLE))
1655 size = 40;
1656 else
1657 size = 36;
1658
1659 result = brasero_mmc1_read_track_info (handle,
1660 track_num,
1661 &track_info,
1662 &size,
1663 code);
1664
1665 if (result != BRASERO_SCSI_OK) {
1666 BRASERO_MEDIA_LOG ("READ TRACK INFO failed");
1667 return FALSE;
1668 }
1669
1670 track->blocks_num = BRASERO_GET_32 (track_info.track_size);
1671 track->session = BRASERO_SCSI_SESSION_NUM (track_info);
1672
1673 if (track->blocks_num <= 300) {
1674 /* Now here is a potential bug: we can write tracks (data or
1675 * not) shorter than 300 KiB /2 sec but they will be padded to
1676 * reach this floor value. It means that blocks_num is always
1677 * 300 blocks even if the data length on the track is actually
1678 * shorter.
1679 * So we read the volume descriptor. If it works, good otherwise
1680 * use the old value.
1681 * That's important for checksuming to have a perfect account of
1682 * the data size. */
1683 BRASERO_MEDIA_LOG ("300 sectors size. Checking for real size");
1684 brasero_medium_track_volume_size (self, track, handle);
1685 }
1686 /* NOTE: for multisession CDs only
1687 * if the session was incremental (TAO/packet/...) by opposition to DAO
1688 * and SAO, then 2 blocks (run-out) have been added at the end of user
1689 * track for linking. That's why we have 2 additional sectors when the
1690 * track has been recorded in TAO mode
1691 * See MMC5
1692 * 6.44.3.2 CD-R Fixed Packet, Variable Packet, Track-At-Once
1693 * Now, strangely track_get_info always removes two blocks, whereas read
1694 * raw toc adds them (always) and this, whatever the mode, the position.
1695 * It means that when we detect a SAO session we have to add 2 blocks to
1696 * all tracks in it.
1697 * See # for any information:
1698 * if first track is recorded in SAO/DAO then the length will be two sec
1699 * shorter. If not, if it was recorded in TAO, that's fine.
1700 * The other way would be to use read raw toc but then that's the
1701 * opposite that happens and that latter will return two more bytes for
1702 * TAO recorded session.
1703 * So there are 2 workarounds:
1704 * - read the volume size (can be unreliable)
1705 * - read the 2 last blocks and see if they are run-outs
1706 * here we do solution 2 but only for CDRW, not blank, and for first
1707 * session only since that's the only one that can be recorded in DAO. */
1708 else if (track->session == 1
1709 && (track->type & BRASERO_MEDIUM_TRACK_DATA)
1710 && multisession
1711 && (priv->info & BRASERO_MEDIUM_CD)
1712 && !(priv->info & BRASERO_MEDIUM_ROM)) {
1713 BRASERO_MEDIA_LOG ("Data track belongs to first session of multisession CD. "
1714 "Checking for real size (%i sectors currently).",
1715 track->blocks_num);
1716
1717 /* we test the pregaps blocks for TDB: these are special blocks
1718 * filling the pregap of a track when it was recorded as TAO or
1719 * as Packet.
1720 * NOTE: in this case we need to skip 7 sectors before since if
1721 * it was recorded incrementally then there is also 4 runins,
1722 * 1 link sector and 2 runouts (at end of pregap).
1723 * we also make sure that the two blocks we're adding are
1724 * actually readable. */
1725 /* Test the last block, the before last and the one before before last */
1726 result = brasero_mmc1_read_block (handle,
1727 FALSE,
1728 BRASERO_SCSI_BLOCK_TYPE_ANY,
1729 BRASERO_SCSI_BLOCK_HEADER_NONE,
1730 BRASERO_SCSI_BLOCK_NO_SUBCHANNEL,
1731 track->blocks_num + track->start,
1732 2,
1733 NULL,
1734 0,
1735 NULL);
1736
1737 if (result == BRASERO_SCSI_OK) {
1738 BRASERO_MEDIA_LOG ("Following two sectors are readable.");
1739
1740 if (brasero_medium_track_written_SAO (handle, track_num, track->start)) {
1741 track->blocks_num += 2;
1742 BRASERO_MEDIA_LOG ("Correcting track size (now %i)", track->blocks_num);
1743 }
1744 }
1745 else
1746 BRASERO_MEDIA_LOG ("Detected runouts");
1747 }
1748
1749 /* NOTE: DVD+RW, DVD-RW (restricted overwrite) never reach this function */
1750 BRASERO_MEDIA_LOG ("Track %i (session %i): type = %i start = %llu size = %llu",
1751 track_num,
1752 track->session,
1753 track->type,
1754 track->start,
1755 track->blocks_num);
1756
1757 return TRUE;
1758 }
1759
1760 static gboolean
brasero_medium_track_set_leadout_DVDR_blank(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroMediumTrack * leadout,BraseroScsiErrCode * code)1761 brasero_medium_track_set_leadout_DVDR_blank (BraseroMedium *self,
1762 BraseroDeviceHandle *handle,
1763 BraseroMediumTrack *leadout,
1764 BraseroScsiErrCode *code)
1765 {
1766 BraseroScsiFormatCapacitiesHdr *hdr = NULL;
1767 BraseroScsiMaxCapacityDesc *current;
1768 BraseroMediumPrivate *priv;
1769 BraseroScsiResult result;
1770 int size;
1771
1772 priv = BRASERO_MEDIUM_PRIVATE (self);
1773
1774 BRASERO_MEDIA_LOG ("Using fallback method for blank CDR to retrieve NWA and leadout information");
1775
1776 /* NWA is easy for blank DVD-Rs, it's 0. So far, so good... */
1777 priv->next_wr_add = 0;
1778
1779 result = brasero_mmc2_read_format_capacities (handle,
1780 &hdr,
1781 &size,
1782 code);
1783 if (result != BRASERO_SCSI_OK) {
1784 BRASERO_MEDIA_LOG ("READ FORMAT CAPACITIES failed");
1785 return FALSE;
1786 }
1787
1788 /* See if the media is already formatted which means for -R media that
1789 * they are blank. */
1790 current = hdr->max_caps;
1791 if (current->type & BRASERO_SCSI_DESC_FORMATTED) {
1792 BRASERO_MEDIA_LOG ("Formatted medium");
1793 g_free (hdr);
1794 return FALSE;
1795 }
1796
1797 BRASERO_MEDIA_LOG ("Unformatted medium");
1798
1799 /* of course it starts at 0 since it's empty */
1800 leadout->start = 0;
1801 leadout->blocks_num = BRASERO_GET_32 (current->blocks_num);
1802
1803 BRASERO_MEDIA_LOG ("Leadout (through READ FORMAT CAPACITIES): start = %llu size = %llu",
1804 leadout->start,
1805 leadout->blocks_num);
1806
1807 g_free (hdr);
1808 return TRUE;
1809 }
1810
1811 static gboolean
brasero_medium_track_set_leadout_CDR_blank(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroMediumTrack * leadout,BraseroScsiErrCode * code)1812 brasero_medium_track_set_leadout_CDR_blank (BraseroMedium *self,
1813 BraseroDeviceHandle *handle,
1814 BraseroMediumTrack *leadout,
1815 BraseroScsiErrCode *code)
1816 {
1817 BraseroScsiAtipData *atip = NULL;
1818 BraseroMediumPrivate *priv;
1819 BraseroScsiResult result;
1820 int size = 0;
1821
1822 priv = BRASERO_MEDIUM_PRIVATE (self);
1823
1824 BRASERO_MEDIA_LOG ("Using fallback method for blank CDR to retrieve NWA and leadout information");
1825
1826 /* NWA is easy for blank CDRs, it's 0. So far, so good... */
1827 priv->next_wr_add = 0;
1828
1829 result = brasero_mmc1_read_atip (handle, &atip, &size, code);
1830 if (result != BRASERO_SCSI_OK) {
1831 BRASERO_MEDIA_LOG ("READ ATIP failed");
1832 return FALSE;
1833 }
1834
1835 leadout->blocks_num = atip->desc->leadout_mn * 60 * 75 +
1836 atip->desc->leadout_sec * 75 +
1837 atip->desc->leadout_frame;
1838
1839 /* of course it starts at 0 since it's empty */
1840 leadout->start = 0;
1841
1842 BRASERO_MEDIA_LOG ("Leadout (through READ ATIP): start = %llu size = %llu",
1843 leadout->start,
1844 leadout->blocks_num);
1845
1846 g_free (atip);
1847
1848 return TRUE;
1849 }
1850
1851 static gboolean
brasero_medium_track_set_leadout(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroMediumTrack * leadout,BraseroScsiErrCode * code)1852 brasero_medium_track_set_leadout (BraseroMedium *self,
1853 BraseroDeviceHandle *handle,
1854 BraseroMediumTrack *leadout,
1855 BraseroScsiErrCode *code)
1856 {
1857 BraseroScsiTrackInfo track_info;
1858 BraseroMediumPrivate *priv;
1859 BraseroScsiResult result;
1860 gint track_num;
1861 int size;
1862
1863 BRASERO_MEDIA_LOG ("Retrieving NWA and leadout information");
1864
1865 priv = BRASERO_MEDIUM_PRIVATE (self);
1866
1867 if (BRASERO_MEDIUM_RANDOM_WRITABLE (priv->info)) {
1868 BRASERO_MEDIA_LOG ("Overwritable medium => skipping");
1869 return TRUE;
1870 }
1871
1872 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDR)) {
1873 /* This is necessary to make sure nwa won't be the start of the
1874 * pregap if the current write mode is SAO with blank CDR.
1875 * Carry on even if it fails.
1876 * This can work with CD-R/W and DVD-R/W. + media don't use the
1877 * write mode page anyway. */
1878 result = brasero_medium_set_write_mode_page_tao (self, handle, code);
1879 if (result == FALSE
1880 && BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK))
1881 return brasero_medium_track_set_leadout_CDR_blank (self,
1882 handle,
1883 leadout,
1884 code);
1885 }
1886
1887 /* At this point we know the type of the disc that's why we set the
1888 * size according to this type. That may help to avoid outrange address
1889 * errors. */
1890 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DUAL_L|BRASERO_MEDIUM_WRITABLE))
1891 size = 48;
1892 else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_PLUS|BRASERO_MEDIUM_WRITABLE))
1893 size = 40;
1894 else
1895 size = 36;
1896
1897 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDR)
1898 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDRW)
1899 /* The following includes DL */
1900 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDR_PLUS))
1901 track_num = 0xFF;
1902 else if (priv->first_open_track >= 0)
1903 track_num = priv->first_open_track;
1904 else {
1905 BRASERO_MEDIA_LOG ("There aren't any open session set");
1906 return FALSE;
1907 }
1908
1909 result = brasero_mmc1_read_track_info (handle,
1910 track_num,
1911 &track_info,
1912 &size,
1913 code);
1914 if (result != BRASERO_SCSI_OK) {
1915 BRASERO_MEDIA_LOG ("READ TRACK INFO failed");
1916
1917 /* This only for CD-R */
1918 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDR|BRASERO_MEDIUM_BLANK))
1919 return brasero_medium_track_set_leadout_CDR_blank (self,
1920 handle,
1921 leadout,
1922 code);
1923 else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BLANK))
1924 return brasero_medium_track_set_leadout_DVDR_blank (self,
1925 handle,
1926 leadout,
1927 code);
1928
1929 return FALSE;
1930 }
1931
1932 BRASERO_MEDIA_LOG ("Next Writable Address is %d", BRASERO_GET_32 (track_info.next_wrt_address));
1933 if (track_info.next_wrt_address_valid)
1934 priv->next_wr_add = BRASERO_GET_32 (track_info.next_wrt_address);
1935 else
1936 BRASERO_MEDIA_LOG ("Next Writable Address is not valid");
1937
1938 /* Set free space */
1939 BRASERO_MEDIA_LOG ("Free blocks %d", BRASERO_GET_32 (track_info.free_blocks));
1940 leadout->blocks_num = BRASERO_GET_32 (track_info.free_blocks);
1941
1942 if (!leadout->blocks_num) {
1943 leadout->blocks_num = BRASERO_GET_32 (track_info.track_size);
1944 BRASERO_MEDIA_LOG ("Using track size %d", leadout->blocks_num);
1945 }
1946
1947 if (!leadout->blocks_num
1948 && BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BLANK))
1949 return brasero_medium_track_set_leadout_DVDR_blank (self,
1950 handle,
1951 leadout,
1952 code);
1953
1954 BRASERO_MEDIA_LOG ("Leadout: start = %llu size = %llu",
1955 leadout->start,
1956 leadout->blocks_num);
1957
1958 return TRUE;
1959 }
1960
1961 /**
1962 * NOTE: for DVD-R multisession we lose 28688 blocks for each session
1963 * so the capacity is the addition of all session sizes + 28688 for each
1964 * For all multisession DVD-/+R and CDR-RW the remaining size is given
1965 * in the leadout. One exception though with DVD+/-RW.
1966 */
1967
1968 static void
brasero_medium_add_DVD_plus_RW_leadout(BraseroMedium * self)1969 brasero_medium_add_DVD_plus_RW_leadout (BraseroMedium *self)
1970 {
1971 BraseroMediumTrack *leadout;
1972 BraseroMediumPrivate *priv;
1973 gint64 blocks_num;
1974 gint32 start;
1975
1976 priv = BRASERO_MEDIUM_PRIVATE (self);
1977
1978 /* determine the start */
1979 if (priv->tracks) {
1980 BraseroMediumTrack *track;
1981
1982 track = priv->tracks->data;
1983 start = track->start + track->blocks_num;
1984 blocks_num = priv->block_num - ((track->blocks_num > 300) ? track->blocks_num : 300);
1985 }
1986 else {
1987 start = 0;
1988 blocks_num = priv->block_num;
1989 }
1990
1991 leadout = g_new0 (BraseroMediumTrack, 1);
1992 priv->tracks = g_slist_append (priv->tracks, leadout);
1993
1994 leadout->start = start;
1995 leadout->blocks_num = blocks_num;
1996 leadout->type = BRASERO_MEDIUM_TRACK_LEADOUT;
1997
1998 /* we fabricate the leadout here. We don't really need one in
1999 * fact since it is always at the last sector whatever the
2000 * amount of data written. So we need in fact to read the file
2001 * system and get the last sector from it. Hopefully it won't be
2002 * buggy */
2003 priv->next_wr_add = 0;
2004
2005 BRASERO_MEDIA_LOG ("Adding fabricated leadout start = %llu length = %llu",
2006 leadout->start,
2007 leadout->blocks_num);
2008 }
2009
2010 static gboolean
brasero_medium_get_sessions_info(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2011 brasero_medium_get_sessions_info (BraseroMedium *self,
2012 BraseroDeviceHandle *handle,
2013 BraseroScsiErrCode *code)
2014 {
2015 int num, i, size;
2016 gboolean multisession;
2017 BraseroScsiResult result;
2018 BraseroScsiTocDesc *desc;
2019 BraseroMediumPrivate *priv;
2020 BraseroScsiFormattedTocData *toc = NULL;
2021
2022 BRASERO_MEDIA_LOG ("Reading Toc");
2023
2024 priv = BRASERO_MEDIUM_PRIVATE (self);
2025
2026 tryagain:
2027
2028 result = brasero_mmc1_read_toc_formatted (handle,
2029 0,
2030 &toc,
2031 &size,
2032 code);
2033 if (result != BRASERO_SCSI_OK) {
2034 BRASERO_MEDIA_LOG ("READ TOC failed");
2035 return FALSE;
2036 }
2037
2038 if (priv->probe_cancelled) {
2039 g_free (toc);
2040 return FALSE;
2041 }
2042
2043 /* My drive with some Video CDs gets a size of 2 (basically the size
2044 * member of the structure) without any error. Consider the drive is not
2045 * ready and needs retrying */
2046 if (size < sizeof (BraseroScsiFormattedTocData)) {
2047 g_free (toc);
2048 toc = NULL;
2049 goto tryagain;
2050 }
2051
2052 num = (size - sizeof (BraseroScsiFormattedTocData)) /
2053 sizeof (BraseroScsiTocDesc);
2054
2055 /* remove 1 for leadout */
2056 multisession = !(priv->info & BRASERO_MEDIUM_BLANK) && num > 0;
2057
2058 /* NOTE: in the case of DVD- there are always only 3 sessions if they
2059 * are open: all first concatenated sessions, the last session, and the
2060 * leadout. */
2061
2062 BRASERO_MEDIA_LOG ("%i track(s) found", num);
2063
2064 desc = toc->desc;
2065 for (i = 0; i < num; i ++, desc ++) {
2066 BraseroMediumTrack *track;
2067
2068 if (desc->track_num == BRASERO_SCSI_TRACK_LEADOUT_START) {
2069 BRASERO_MEDIA_LOG ("Leadout reached %d",
2070 BRASERO_GET_32 (desc->track_start));
2071 break;
2072 }
2073
2074 track = g_new0 (BraseroMediumTrack, 1);
2075 priv->tracks = g_slist_prepend (priv->tracks, track);
2076 track->start = BRASERO_GET_32 (desc->track_start);
2077
2078 /* we shouldn't request info on a track if the disc is closed */
2079 if (desc->control & BRASERO_SCSI_TRACK_COPY)
2080 track->type |= BRASERO_MEDIUM_TRACK_COPY;
2081
2082 if (!(desc->control & BRASERO_SCSI_TRACK_DATA)) {
2083 track->type |= BRASERO_MEDIUM_TRACK_AUDIO;
2084 priv->info |= BRASERO_MEDIUM_HAS_AUDIO;
2085
2086 if (desc->control & BRASERO_SCSI_TRACK_PREEMP)
2087 track->type |= BRASERO_MEDIUM_TRACK_PREEMP;
2088
2089 if (desc->control & BRASERO_SCSI_TRACK_4_CHANNELS)
2090 track->type |= BRASERO_MEDIUM_TRACK_4_CHANNELS;
2091 }
2092 else {
2093 track->type |= BRASERO_MEDIUM_TRACK_DATA;
2094 priv->info |= BRASERO_MEDIUM_HAS_DATA;
2095
2096 if (desc->control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL)
2097 track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL;
2098 }
2099
2100 if (BRASERO_MEDIUM_RANDOM_WRITABLE (priv->info)) {
2101 gboolean result;
2102
2103 /* A special case for these kinds of media (DVD+RW, ...)
2104 * which have only one track: the first. Since it's not
2105 * possible to know the amount of data that were really
2106 * written in this session, read the filesystem. */
2107 BRASERO_MEDIA_LOG ("DVD+RW (DL) or DVD-RW (restricted overwrite) checking volume size (start = %i)", track->start);
2108 track->session = 1;
2109 track->start = 0;
2110 result = brasero_medium_track_volume_size (self,
2111 track,
2112 handle);
2113 if (result != TRUE) {
2114 priv->tracks = g_slist_remove (priv->tracks, track);
2115 g_free (track);
2116
2117 priv->info |= BRASERO_MEDIUM_BLANK;
2118 priv->info &= ~(BRASERO_MEDIUM_CLOSED|
2119 BRASERO_MEDIUM_HAS_DATA);
2120
2121 BRASERO_MEDIA_LOG ("Empty first session.");
2122 }
2123 else {
2124 priv->next_wr_add = 0;
2125 BRASERO_MEDIA_LOG ("Track 1 (session %i): type = %i start = %llu size = %llu",
2126 track->session,
2127 track->type,
2128 track->start,
2129 track->blocks_num);
2130 }
2131
2132 /* NOTE: the next track should be the leadout */
2133 continue;
2134 }
2135
2136 if (priv->probe_cancelled) {
2137 g_free (toc);
2138 return FALSE;
2139 }
2140
2141 brasero_medium_track_get_info (self,
2142 multisession,
2143 track,
2144 g_slist_length (priv->tracks),
2145 handle,
2146 code);
2147 }
2148
2149 if (priv->probe_cancelled) {
2150 g_free (toc);
2151 return FALSE;
2152 }
2153
2154 /* put the tracks in the right order */
2155 priv->tracks = g_slist_reverse (priv->tracks);
2156
2157 if (BRASERO_MEDIUM_RANDOM_WRITABLE (priv->info))
2158 brasero_medium_add_DVD_plus_RW_leadout (self);
2159 else if (!(priv->info & BRASERO_MEDIUM_CLOSED)) {
2160 BraseroMediumTrack *leadout;
2161
2162 /* we shouldn't request info on leadout if the disc is closed
2163 * (except for DVD+/- (restricted) RW (see above) */
2164 leadout = g_new0 (BraseroMediumTrack, 1);
2165 leadout->start = BRASERO_GET_32 (desc->track_start);
2166 leadout->type = BRASERO_MEDIUM_TRACK_LEADOUT;
2167 priv->tracks = g_slist_append (priv->tracks, leadout);
2168
2169 brasero_medium_track_set_leadout (self,
2170 handle,
2171 leadout,
2172 code);
2173 }
2174
2175 g_free (toc);
2176
2177 return TRUE;
2178 }
2179
2180 static void
brasero_medium_get_DVD_id(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2181 brasero_medium_get_DVD_id (BraseroMedium *self,
2182 BraseroDeviceHandle *handle,
2183 BraseroScsiErrCode *code)
2184 {
2185 gint size = 0;
2186 BraseroScsiResult result;
2187 BraseroMediumPrivate *priv;
2188 BraseroScsiReadDiscStructureHdr *hdr = NULL;
2189
2190 priv = BRASERO_MEDIUM_PRIVATE (self);
2191
2192 /* This should be only possible for DVD-R(W) and not with all drives */
2193 result = brasero_mmc2_read_generic_structure (handle,
2194 BRASERO_SCSI_FORMAT_LESS_MEDIA_ID_DVD,
2195 &hdr,
2196 &size,
2197 code);
2198 if (result != BRASERO_SCSI_OK) {
2199 BRASERO_MEDIA_LOG ("Retrieval of DVD id failed");
2200 return;
2201 }
2202
2203 BRASERO_MEDIA_LOG ("DVD id %d", BRASERO_GET_16 (hdr->data + 2));
2204 priv->id = g_strdup_printf ("%d", BRASERO_GET_16 (hdr->data + 2));
2205 g_free (hdr);
2206 }
2207
2208 static gboolean
brasero_medium_set_blank(BraseroMedium * self,BraseroDeviceHandle * handle,gint first_open_track,BraseroScsiErrCode * code)2209 brasero_medium_set_blank (BraseroMedium *self,
2210 BraseroDeviceHandle *handle,
2211 gint first_open_track,
2212 BraseroScsiErrCode *code)
2213 {
2214 BraseroMediumPrivate *priv;
2215 BraseroMediumTrack *track;
2216
2217 priv = BRASERO_MEDIUM_PRIVATE (self);
2218
2219 BRASERO_MEDIA_LOG ("Empty media");
2220
2221 priv->info |= BRASERO_MEDIUM_BLANK;
2222 priv->block_size = 2048;
2223
2224 priv->first_open_track = first_open_track;
2225 BRASERO_MEDIA_LOG ("First open track %d", priv->first_open_track);
2226
2227 if (BRASERO_MEDIUM_RANDOM_WRITABLE (priv->info))
2228 brasero_medium_add_DVD_plus_RW_leadout (self);
2229 else {
2230 track = g_new0 (BraseroMediumTrack, 1);
2231 track->start = 0;
2232 track->type = BRASERO_MEDIUM_TRACK_LEADOUT;
2233 priv->tracks = g_slist_prepend (priv->tracks, track);
2234
2235 brasero_medium_track_set_leadout (self,
2236 handle,
2237 track,
2238 code);
2239 }
2240
2241 return TRUE;
2242 }
2243
2244 static gboolean
brasero_medium_get_contents(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2245 brasero_medium_get_contents (BraseroMedium *self,
2246 BraseroDeviceHandle *handle,
2247 BraseroScsiErrCode *code)
2248 {
2249 int size;
2250 gboolean res = TRUE;
2251 BraseroScsiResult result;
2252 BraseroMediumPrivate *priv;
2253 BraseroScsiDiscInfoStd *info = NULL;
2254
2255 BRASERO_MEDIA_LOG ("Retrieving media status");
2256
2257 priv = BRASERO_MEDIUM_PRIVATE (self);
2258
2259 result = brasero_mmc1_read_disc_information_std (handle,
2260 &info,
2261 &size,
2262 code);
2263 if (result != BRASERO_SCSI_OK) {
2264 BRASERO_MEDIA_LOG ("READ DISC INFORMATION failed");
2265 return FALSE;
2266 }
2267
2268 if (info->disc_id_valid) {
2269 /* Try to get the disc identification if possible (CDs only) */
2270 BRASERO_MEDIA_LOG ("Disc id %i", BRASERO_GET_32 (info->disc_id));
2271 priv->id = g_strdup_printf ("%d", BRASERO_GET_32 (info->disc_id));
2272 }
2273 else if (priv->info & BRASERO_MEDIUM_DVD)
2274 brasero_medium_get_DVD_id (self, handle, code);
2275
2276 if (info->erasable)
2277 priv->info |= BRASERO_MEDIUM_REWRITABLE;
2278
2279 priv->first_open_track = -1;
2280
2281 if (info->status == BRASERO_SCSI_DISC_EMPTY) {
2282 res = brasero_medium_set_blank (self,
2283 handle,
2284 BRASERO_FIRST_TRACK_IN_LAST_SESSION (info),
2285 code);
2286 }
2287 else if (info->status == BRASERO_SCSI_DISC_INCOMPLETE) {
2288 if (!BRASERO_MEDIUM_RANDOM_WRITABLE (priv->info)) {
2289 priv->info |= BRASERO_MEDIUM_APPENDABLE;
2290
2291 /* This is just to make sure the disc is in a correct
2292 * state as I saw some drive being flagged as unformatted
2293 * appendable */
2294 priv->info &= ~(BRASERO_MEDIUM_UNFORMATTED);
2295
2296 BRASERO_MEDIA_LOG ("Appendable media");
2297
2298 priv->first_open_track = BRASERO_FIRST_TRACK_IN_LAST_SESSION (info);
2299 BRASERO_MEDIA_LOG ("First track in last open session %d", priv->first_open_track);
2300
2301 res = brasero_medium_get_sessions_info (self, handle, code);
2302 }
2303 else {
2304 /* if that type of media is in incomplete state that
2305 * means it has just been formatted. And therefore it's
2306 * blank. */
2307 res = brasero_medium_set_blank (self,
2308 handle,
2309 BRASERO_FIRST_TRACK_IN_LAST_SESSION (info),
2310 code);
2311 }
2312 }
2313 else if (info->status == BRASERO_SCSI_DISC_FINALIZED) {
2314 priv->info |= BRASERO_MEDIUM_CLOSED;
2315 BRASERO_MEDIA_LOG ("Closed media");
2316
2317 res = brasero_medium_get_sessions_info (self, handle, code);
2318 }
2319
2320 g_free (info);
2321 return res;
2322 }
2323
2324 /**
2325 * Some identification functions
2326 */
2327
2328 static gboolean
brasero_medium_get_medium_type(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2329 brasero_medium_get_medium_type (BraseroMedium *self,
2330 BraseroDeviceHandle *handle,
2331 BraseroScsiErrCode *code)
2332 {
2333 BraseroScsiProfile profile;
2334 BraseroMediumPrivate *priv;
2335 BraseroScsiResult result;
2336
2337 BRASERO_MEDIA_LOG ("Retrieving media profile");
2338
2339 priv = BRASERO_MEDIUM_PRIVATE (self);
2340 result = brasero_mmc2_get_profile (handle, &profile, code);
2341
2342 if (result != BRASERO_SCSI_OK) {
2343 BraseroScsiAtipData *data = NULL;
2344 int size = 0;
2345
2346 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
2347
2348 /* This could be a MMC1 drive since this command was
2349 * introduced in MMC2 and is supported onward. So it
2350 * has to be a CD (R/RW). The rest of the information
2351 * will be provided by read_disc_information. */
2352
2353 /* retrieve the speed */
2354 result = brasero_medium_get_page_2A_write_speed_desc (self,
2355 handle,
2356 code);
2357
2358 /* If this fails it means that this drive is probably older than
2359 * MMC1 spec or does not conform to it. */
2360 if (result != TRUE) {
2361 priv->info = BRASERO_MEDIUM_NONE;
2362 return FALSE;
2363 }
2364
2365 /* The only thing here left to determine is if that's a WRITABLE
2366 * or a REWRITABLE. To determine that information, we need to
2367 * read TocPmaAtip. It if fails that's a ROM, if it succeeds.
2368 * No need to set error code since we consider that it's a ROM
2369 * if a failure happens. */
2370 result = brasero_mmc1_read_atip (handle,
2371 &data,
2372 &size,
2373 NULL);
2374 if (result != BRASERO_SCSI_OK) {
2375 /* CD-ROM */
2376 priv->info = BRASERO_MEDIUM_CDROM;
2377 priv->type = types [1];
2378 }
2379 else {
2380 /* check the size of the structure: it must be at least 8 bytes long */
2381 if (size < 8) {
2382 if (size)
2383 g_free (data);
2384
2385 BRASERO_MEDIA_LOG ("READ ATIP failed (wrong size)");
2386 return FALSE;
2387 }
2388
2389 if (data->desc->erasable) {
2390 /* CDRW */
2391 priv->info = BRASERO_MEDIUM_CDRW;
2392 priv->type = types [3];
2393 }
2394 else {
2395 /* CDR */
2396 priv->info = BRASERO_MEDIUM_CDR;
2397 priv->type = types [2];
2398 }
2399
2400 g_free (data);
2401 }
2402
2403 return result;
2404 }
2405
2406 switch (profile) {
2407 case BRASERO_SCSI_PROF_EMPTY:
2408 priv->info = BRASERO_MEDIUM_NONE;
2409 return FALSE;
2410
2411 case BRASERO_SCSI_PROF_CDROM:
2412 priv->info = BRASERO_MEDIUM_CDROM;
2413 priv->type = types [1];
2414 break;
2415
2416 case BRASERO_SCSI_PROF_CDR:
2417 priv->info = BRASERO_MEDIUM_CDR;
2418 priv->type = types [2];
2419 break;
2420
2421 case BRASERO_SCSI_PROF_CDRW:
2422 priv->info = BRASERO_MEDIUM_CDRW;
2423 priv->type = types [3];
2424 break;
2425
2426 case BRASERO_SCSI_PROF_DVD_ROM:
2427 priv->info = BRASERO_MEDIUM_DVD_ROM;
2428 priv->type = types [4];
2429 break;
2430
2431 case BRASERO_SCSI_PROF_DVD_R:
2432 priv->info = BRASERO_MEDIUM_DVDR;
2433 priv->type = types [5];
2434 break;
2435
2436 case BRASERO_SCSI_PROF_DVD_RW_RESTRICTED:
2437 priv->info = BRASERO_MEDIUM_DVDRW_RESTRICTED;
2438 priv->type = types [6];
2439 break;
2440
2441 case BRASERO_SCSI_PROF_DVD_RW_SEQUENTIAL:
2442 priv->info = BRASERO_MEDIUM_DVDRW;
2443 priv->type = types [6];
2444 break;
2445
2446 case BRASERO_SCSI_PROF_DVD_R_PLUS:
2447 priv->info = BRASERO_MEDIUM_DVDR_PLUS;
2448 priv->type = types [7];
2449 break;
2450
2451 case BRASERO_SCSI_PROF_DVD_RW_PLUS:
2452 priv->info = BRASERO_MEDIUM_DVDRW_PLUS;
2453 priv->type = types [8];
2454 break;
2455
2456 case BRASERO_SCSI_PROF_DVD_R_PLUS_DL:
2457 priv->info = BRASERO_MEDIUM_DVDR_PLUS_DL;
2458 priv->type = types [9];
2459 break;
2460
2461 case BRASERO_SCSI_PROF_DVD_RW_PLUS_DL:
2462 priv->info = BRASERO_MEDIUM_DVDRW_PLUS_DL;
2463 priv->type = types [10];
2464 break;
2465
2466 case BRASERO_SCSI_PROF_DVD_R_DL_SEQUENTIAL:
2467 priv->info = BRASERO_MEDIUM_DVDR_DL;
2468 priv->type = types [11];
2469 break;
2470
2471 case BRASERO_SCSI_PROF_DVD_R_DL_JUMP:
2472 priv->info = BRASERO_MEDIUM_DVDR_JUMP_DL;
2473 priv->type = types [11];
2474 break;
2475
2476 case BRASERO_SCSI_PROF_BD_ROM:
2477 priv->info = BRASERO_MEDIUM_BD_ROM;
2478 priv->type = types [13];
2479 break;
2480
2481 case BRASERO_SCSI_PROF_BR_R_SEQUENTIAL:
2482 /* check if that's a POW later */
2483 priv->info = BRASERO_MEDIUM_BDR_SRM;
2484 priv->type = types [14];
2485 break;
2486
2487 case BRASERO_SCSI_PROF_BR_R_RANDOM:
2488 priv->info = BRASERO_MEDIUM_BDR_RANDOM;
2489 priv->type = types [14];
2490 break;
2491
2492 case BRASERO_SCSI_PROF_BD_RW:
2493 priv->info = BRASERO_MEDIUM_BDRE;
2494 priv->type = types [15];
2495 break;
2496
2497 case BRASERO_SCSI_PROF_DVD_RAM:
2498 priv->info = BRASERO_MEDIUM_DVD_RAM;
2499 priv->type = types [12];
2500 break;
2501
2502 /* WARNING: these types are recognized, no more */
2503 case BRASERO_SCSI_PROF_NON_REMOVABLE:
2504 case BRASERO_SCSI_PROF_REMOVABLE:
2505 case BRASERO_SCSI_PROF_MO_ERASABLE:
2506 case BRASERO_SCSI_PROF_MO_WRITE_ONCE:
2507 case BRASERO_SCSI_PROF_MO_ADVANCED_STORAGE:
2508 case BRASERO_SCSI_PROF_DDCD_ROM:
2509 case BRASERO_SCSI_PROF_DDCD_R:
2510 case BRASERO_SCSI_PROF_DDCD_RW:
2511 case BRASERO_SCSI_PROF_HD_DVD_ROM:
2512 case BRASERO_SCSI_PROF_HD_DVD_R:
2513 case BRASERO_SCSI_PROF_HD_DVD_RAM:
2514 priv->info = BRASERO_MEDIUM_UNSUPPORTED;
2515 return FALSE;
2516 }
2517
2518 /* Get a more precise idea of what sequential BD-R type we have here */
2519 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BDR_SRM)) {
2520 BraseroScsiGetConfigHdr *hdr = NULL;
2521 int size = 0;
2522
2523 /* check for POW type */
2524 result = brasero_mmc2_get_configuration_feature (handle,
2525 BRASERO_SCSI_FEAT_BDR_POW,
2526 &hdr,
2527 &size,
2528 code);
2529 if (result == BRASERO_SCSI_OK) {
2530 if (hdr->desc->current) {
2531 BRASERO_MEDIA_LOG ("POW formatted medium detected");
2532 priv->info |= BRASERO_MEDIUM_POW;
2533 }
2534
2535 g_free (hdr);
2536 }
2537 else {
2538 BraseroScsiFormatCapacitiesHdr *hdr = NULL;
2539
2540 /* NOTE: the disc status as far as format is concerned
2541 * is done later for all rewritable media. */
2542 /* check for unformatted media (if it's POW or RANDOM
2543 * there is no need of course) */
2544 result = brasero_mmc2_read_format_capacities (handle,
2545 &hdr,
2546 &size,
2547 NULL);
2548 if (result == BRASERO_SCSI_OK) {
2549 BraseroScsiMaxCapacityDesc *current;
2550
2551 current = hdr->max_caps;
2552 if (!(current->type & BRASERO_SCSI_DESC_FORMATTED)) {
2553 BRASERO_MEDIA_LOG ("Unformatted BD-R");
2554 priv->info |= BRASERO_MEDIUM_UNFORMATTED;
2555 }
2556
2557 g_free (hdr);
2558 }
2559 }
2560 }
2561
2562 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BD)) {
2563 /* FIXME: check for dual layer BD */
2564 }
2565
2566 return TRUE;
2567 }
2568
2569 static gboolean
brasero_medium_get_css_feature(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2570 brasero_medium_get_css_feature (BraseroMedium *self,
2571 BraseroDeviceHandle *handle,
2572 BraseroScsiErrCode *code)
2573 {
2574 BraseroScsiGetConfigHdr *hdr = NULL;
2575 BraseroMediumPrivate *priv;
2576 BraseroScsiResult result;
2577 int size;
2578
2579 priv = BRASERO_MEDIUM_PRIVATE (self);
2580
2581 BRASERO_MEDIA_LOG ("Testing for Css encrypted media");
2582 result = brasero_mmc2_get_configuration_feature (handle,
2583 BRASERO_SCSI_FEAT_DVD_CSS,
2584 &hdr,
2585 &size,
2586 code);
2587 if (result != BRASERO_SCSI_OK) {
2588 BRASERO_MEDIA_LOG ("GET CONFIGURATION failed");
2589 return FALSE;
2590 }
2591
2592 if (hdr->desc->add_len < sizeof (BraseroScsiDVDCssDesc)) {
2593 g_free (hdr);
2594 return TRUE;
2595 }
2596
2597 /* here we just need to see if this feature is current or not */
2598 if (hdr->desc->current) {
2599 priv->info |= BRASERO_MEDIUM_PROTECTED;
2600 BRASERO_MEDIA_LOG ("media is Css protected");
2601 }
2602
2603 g_free (hdr);
2604 return TRUE;
2605 }
2606
2607 static gboolean
brasero_medium_get_CD_TEXT(BraseroMedium * medium,int type,int track_num,guint charset_CD_TEXT,gboolean double_byte,const char * string)2608 brasero_medium_get_CD_TEXT (BraseroMedium *medium,
2609 int type,
2610 int track_num,
2611 guint charset_CD_TEXT,
2612 gboolean double_byte,
2613 const char *string)
2614 {
2615 char *utf8_string;
2616 BraseroMediumPrivate *priv;
2617 const gchar *charset = NULL;
2618
2619 priv = BRASERO_MEDIUM_PRIVATE (medium);
2620
2621 /* For the moment we're only interested in medium title but that could
2622 * be extented to all tracks information. */
2623 switch (type) {
2624 case BRASERO_SCSI_CD_TEXT_ALBUM_TITLE:
2625 if (track_num)
2626 return FALSE;
2627
2628 break;
2629
2630 case BRASERO_SCSI_CD_TEXT_PERFORMER_NAME:
2631 case BRASERO_SCSI_CD_TEXT_SONGWRITER_NAME:
2632 case BRASERO_SCSI_CD_TEXT_COMPOSER_NAME:
2633 case BRASERO_SCSI_CD_TEXT_ARRANGER_NAME:
2634 case BRASERO_SCSI_CD_TEXT_ARTIST_NAME:
2635 case BRASERO_SCSI_CD_TEXT_DISC_ID_INFO:
2636 case BRASERO_SCSI_CD_TEXT_GENRE_ID_INFO:
2637 case BRASERO_SCSI_CD_TEXT_UPC_EAN_ISRC:
2638 default:
2639 return FALSE;
2640 }
2641
2642 g_get_charset (&charset);
2643
2644 /* It's ASCII so convert to locale */
2645 switch (charset_CD_TEXT) {
2646 case BRASERO_CD_TEXT_8859_1:
2647 utf8_string = g_convert_with_fallback (string,
2648 -1,
2649 charset,
2650 "ISO-8859-1",
2651 "_",
2652 NULL,
2653 NULL,
2654 NULL);
2655 break;
2656 case BRASERO_CD_TEXT_KANJI:
2657 utf8_string = g_convert_with_fallback (string,
2658 -1,
2659 charset,
2660 "EUC-JP",
2661 "_",
2662 NULL,
2663 NULL,
2664 NULL);
2665 break;
2666 case BRASERO_CD_TEXT_KOREAN:
2667 utf8_string = g_convert_with_fallback (string,
2668 -1,
2669 charset,
2670 "EUC-KR",
2671 "_",
2672 NULL,
2673 NULL,
2674 NULL);
2675 break;
2676 case BRASERO_CD_TEXT_CHINESE:
2677 utf8_string = g_convert_with_fallback (string,
2678 -1,
2679 charset,
2680 "GB2312",
2681 "_",
2682 NULL,
2683 NULL,
2684 NULL);
2685 break;
2686 default:
2687 case BRASERO_CD_TEXT_ASCII:
2688 utf8_string = g_convert_with_fallback (string,
2689 -1,
2690 charset,
2691 "ASCII",
2692 "_",
2693 NULL,
2694 NULL,
2695 NULL);
2696 }
2697
2698
2699 if (priv->CD_TEXT_title)
2700 g_free (priv->CD_TEXT_title);
2701
2702 if (!utf8_string) {
2703 BRASERO_MEDIA_LOG ("Charset convertion failed");
2704 priv->CD_TEXT_title = g_strdup (string);
2705 }
2706 else
2707 priv->CD_TEXT_title = utf8_string;
2708
2709 BRASERO_MEDIA_LOG ("CD-TEXT title %s", priv->CD_TEXT_title);
2710 return TRUE;
2711 }
2712
2713 static int
_next_CD_TEXT_pack(BraseroScsiCDTextData * cd_text,int current,int max)2714 _next_CD_TEXT_pack (BraseroScsiCDTextData *cd_text,
2715 int current,
2716 int max)
2717 {
2718 current ++;
2719 if (current >= max)
2720 return -1;
2721
2722 /* Skip all packs we're not interested or are not valid */
2723 while (cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_ALBUM_TITLE &&
2724 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_PERFORMER_NAME &&
2725 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_SONGWRITER_NAME &&
2726 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_COMPOSER_NAME &&
2727 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_ARRANGER_NAME &&
2728 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_ARTIST_NAME &&
2729 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_DISC_ID_INFO &&
2730 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_GENRE_ID_INFO &&
2731 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_UPC_EAN_ISRC &&
2732 cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_BLOCK_SIZE) {
2733 current ++;
2734 if (current >= max)
2735 return -1;
2736 }
2737
2738 return current;
2739 }
2740
2741 static gboolean
brasero_medium_read_CD_TEXT_block_info(BraseroScsiCDTextData * cd_text,int current,int max,gchar * buffer)2742 brasero_medium_read_CD_TEXT_block_info (BraseroScsiCDTextData *cd_text,
2743 int current,
2744 int max,
2745 gchar *buffer)
2746 {
2747 while ((current = _next_CD_TEXT_pack (cd_text, current, max)) != -1) {
2748 off_t offset = 0;
2749
2750 if (cd_text->pack [current].type != BRASERO_SCSI_CD_TEXT_BLOCK_SIZE)
2751 continue;
2752
2753 do {
2754 memcpy (buffer + offset,
2755 cd_text->pack [current].text,
2756 sizeof (cd_text->pack [current].text));
2757
2758 offset += sizeof (cd_text->pack [current].text);
2759 current = _next_CD_TEXT_pack (cd_text, current, max);
2760 } while (current != -1 && cd_text->pack [current].type == BRASERO_SCSI_CD_TEXT_BLOCK_SIZE);
2761
2762 return TRUE;
2763 }
2764
2765 return FALSE;
2766 }
2767
2768 static void
brasero_medium_read_CD_TEXT(BraseroMedium * self,BraseroDeviceHandle * handle,BraseroScsiErrCode * code)2769 brasero_medium_read_CD_TEXT (BraseroMedium *self,
2770 BraseroDeviceHandle *handle,
2771 BraseroScsiErrCode *code)
2772 {
2773 int off;
2774 gint charset;
2775 int track_num;
2776 int num, size, i;
2777 char buffer [256]; /* mmc specs advise no more than 160 */
2778 gboolean find_block_info;
2779 BraseroScsiCDTextData *cd_text;
2780
2781 BRASERO_MEDIA_LOG ("Getting CD-TEXT");
2782 if (brasero_mmc3_read_cd_text (handle, &cd_text, &size, code) != BRASERO_SCSI_OK) {
2783 BRASERO_MEDIA_LOG ("GET CD-TEXT failed");
2784 return;
2785 }
2786
2787 /* Get the number of CD-Text Data Packs.
2788 * Some drives seem to report an idiotic cd_text->hdr->len. So use size
2789 * to be on a safer side. */
2790 if (size < sizeof (BraseroScsiTocPmaAtipHdr)) {
2791 g_free (cd_text);
2792 return;
2793 }
2794
2795 num = (size - sizeof (BraseroScsiTocPmaAtipHdr)) / sizeof (BraseroScsiCDTextPackData);
2796 if (num <= 0) {
2797 g_free (cd_text);
2798 return;
2799 }
2800
2801 off = 0;
2802 track_num = 0;
2803 charset = BRASERO_CD_TEXT_ASCII;
2804
2805 i = -1;
2806 find_block_info = TRUE;
2807 while ((i = _next_CD_TEXT_pack (cd_text, i, num)) != -1) {
2808 int j;
2809 gboolean is_double_byte;
2810
2811 /* skip these until the start of another language block or the end */
2812 if (cd_text->pack [i].type == BRASERO_SCSI_CD_TEXT_BLOCK_SIZE) {
2813 find_block_info = TRUE;
2814 continue;
2815 }
2816
2817 if (find_block_info) {
2818 find_block_info = FALSE;
2819
2820 /* This pack is important since it holds the charset. */
2821 /* NOTE: it's always the last in a block (max 255
2822 * CD-TEXT pack data). So find it first. */
2823 if (brasero_medium_read_CD_TEXT_block_info (cd_text, i, num, buffer)) {
2824 BraseroScsiCDTextPackCharset *pack;
2825
2826 pack = (BraseroScsiCDTextPackCharset *) buffer;
2827 charset = pack->charset;
2828
2829 BRASERO_MEDIA_LOG ("Found language pack. Charset = %d. Start %d. End %d",
2830 charset, pack->first_track, pack->last_track);
2831 }
2832 }
2833
2834 track_num = cd_text->pack [i].track_num;
2835 is_double_byte = cd_text->pack [i].double_byte;
2836
2837 for (j = 0; j < sizeof (cd_text->pack [i].text); j++) {
2838 if (!off
2839 && cd_text->pack [i].text [j] == '\t'
2840 && (!is_double_byte
2841 || (j+1 < sizeof (cd_text->pack [i].text) && cd_text->pack [i].text [j + 1] == '\t'))) {
2842 /* Specs say that tab character means that's the
2843 * same string as before. So if buffer is not
2844 * empty send the same string. */
2845 if (buffer [0] != '\0')
2846 brasero_medium_get_CD_TEXT (self,
2847 cd_text->pack [i].type,
2848 track_num,
2849 charset,
2850 cd_text->pack [i].double_byte,
2851 buffer);
2852 track_num ++;
2853 continue;
2854 }
2855
2856 buffer [off] = cd_text->pack [i].text [j];
2857 off++;
2858
2859 if (cd_text->pack [i].text [j] == '\0'
2860 && (!is_double_byte
2861 || (j+1 < sizeof (cd_text->pack [i].text) && cd_text->pack [i].text [j + 1] == '\0'))) {
2862 /* Make sure we actually wrote something to the
2863 * buffer and that it's not empty. */
2864 if (buffer [0] != '\0')
2865 brasero_medium_get_CD_TEXT (self,
2866 cd_text->pack [i].type,
2867 track_num,
2868 charset,
2869 cd_text->pack [i].double_byte,
2870 buffer);
2871
2872 /* End of encapsulated Text Pack. Skip to the next. */
2873 track_num ++;
2874 off = 0;
2875 }
2876 }
2877 }
2878
2879 g_free (cd_text);
2880 }
2881
2882 static void
brasero_medium_init_real(BraseroMedium * object,BraseroDeviceHandle * handle)2883 brasero_medium_init_real (BraseroMedium *object,
2884 BraseroDeviceHandle *handle)
2885 {
2886 guint i;
2887 gchar *name;
2888 gboolean result;
2889 BraseroMediumPrivate *priv;
2890 BraseroScsiErrCode code = 0;
2891 gchar buffer [256] = { 0, };
2892
2893 priv = BRASERO_MEDIUM_PRIVATE (object);
2894
2895 name = brasero_drive_get_display_name (priv->drive);
2896 BRASERO_MEDIA_LOG ("Initializing information for medium in %s", name);
2897 g_free (name);
2898
2899 if (priv->probe_cancelled)
2900 return;
2901
2902 result = brasero_medium_get_medium_type (object, handle, &code);
2903 if (result != TRUE)
2904 return;
2905
2906 if (priv->probe_cancelled)
2907 return;
2908
2909 result = brasero_medium_get_speed (object, handle, &code);
2910 if (result != TRUE)
2911 return;
2912
2913 if (priv->probe_cancelled)
2914 return;
2915
2916 brasero_medium_get_capacity_by_type (object, handle, &code);
2917 if (priv->probe_cancelled)
2918 return;
2919
2920 brasero_medium_init_caps (object, handle, &code);
2921 if (priv->probe_cancelled)
2922 return;
2923
2924 if (!brasero_medium_get_contents (object, handle, &code))
2925 return;
2926
2927 if (priv->probe_cancelled)
2928 return;
2929
2930 /* assume that css feature is only for DVD-ROM which might be wrong but
2931 * some drives wrongly reports that css is enabled for blank DVD+R/W */
2932 if (BRASERO_MEDIUM_IS (priv->info, (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_ROM)))
2933 brasero_medium_get_css_feature (object, handle, &code);
2934
2935 if (priv->probe_cancelled)
2936 return;
2937
2938 /* read CD-TEXT title */
2939 if (priv->info & BRASERO_MEDIUM_HAS_AUDIO)
2940 brasero_medium_read_CD_TEXT (object, handle, &code);
2941
2942 if (priv->probe_cancelled)
2943 return;
2944
2945 brasero_media_to_string (priv->info, buffer);
2946 BRASERO_MEDIA_LOG ("media is %s", buffer);
2947
2948 if (!priv->wr_speeds)
2949 return;
2950
2951 /* sort write speeds */
2952 for (i = 0; priv->wr_speeds [i] != 0; i ++) {
2953 guint j;
2954
2955 for (j = 0; priv->wr_speeds [j] != 0; j ++) {
2956 if (priv->wr_speeds [i] > priv->wr_speeds [j]) {
2957 gint64 tmp;
2958
2959 tmp = priv->wr_speeds [i];
2960 priv->wr_speeds [i] = priv->wr_speeds [j];
2961 priv->wr_speeds [j] = tmp;
2962 }
2963 }
2964 }
2965 }
2966
2967 gboolean
brasero_medium_probing(BraseroMedium * medium)2968 brasero_medium_probing (BraseroMedium *medium)
2969 {
2970 BraseroMediumPrivate *priv;
2971
2972 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
2973
2974 priv = BRASERO_MEDIUM_PRIVATE (medium);
2975 return priv->probe != NULL;
2976 }
2977
2978 static gboolean
brasero_medium_probed(gpointer data)2979 brasero_medium_probed (gpointer data)
2980 {
2981 BraseroMediumPrivate *priv;
2982
2983 g_return_val_if_fail (BRASERO_IS_MEDIUM (data), FALSE);
2984
2985 priv = BRASERO_MEDIUM_PRIVATE (data);
2986
2987 priv->probe_id = 0;
2988
2989 /* This signal must be emitted in the main thread */
2990 GDK_THREADS_ENTER ();
2991 g_signal_emit (data,
2992 medium_signals [PROBED],
2993 0);
2994 GDK_THREADS_LEAVE ();
2995
2996 return FALSE;
2997 }
2998
2999 static gpointer
brasero_medium_probe_thread(gpointer self)3000 brasero_medium_probe_thread (gpointer self)
3001 {
3002 gint counter = 0;
3003 GTimeVal wait_time;
3004 const gchar *device;
3005 BraseroScsiErrCode code;
3006 BraseroMediumPrivate *priv;
3007 BraseroDeviceHandle *handle;
3008
3009 priv = BRASERO_MEDIUM_PRIVATE (self);
3010
3011 priv->info = BRASERO_MEDIUM_BUSY;
3012
3013 /* the drive might be busy (a burning is going on) so we don't block
3014 * but we re-try to open it every second */
3015 device = brasero_drive_get_device (priv->drive);
3016 BRASERO_MEDIA_LOG ("Trying to open device %s", device);
3017
3018 handle = brasero_device_handle_open (device, FALSE, &code);
3019 while (!handle && counter <= BRASERO_MEDIUM_OPEN_ATTEMPTS) {
3020 sleep (1);
3021
3022 if (priv->probe_cancelled)
3023 goto end;
3024
3025 counter ++;
3026 handle = brasero_device_handle_open (device, FALSE, &code);
3027 }
3028
3029 if (!handle) {
3030 BRASERO_MEDIA_LOG ("Open () failed: medium busy");
3031 goto end;
3032 }
3033
3034 if (priv->probe_cancelled) {
3035 brasero_device_handle_close (handle);
3036 goto end;
3037 }
3038
3039 BRASERO_MEDIA_LOG ("Open () succeeded");
3040
3041 /* NOTE: if we wanted to know the status we'd need to read the
3042 * error code variable which is currently NULL */
3043 while (brasero_spc1_test_unit_ready (handle, &code) != BRASERO_SCSI_OK) {
3044 if (code == BRASERO_SCSI_NO_MEDIUM) {
3045 BRASERO_MEDIA_LOG ("No medium inserted");
3046 priv->info = BRASERO_MEDIUM_NONE;
3047
3048 brasero_device_handle_close (handle);
3049 goto end;
3050 }
3051 else if (code != BRASERO_SCSI_NOT_READY) {
3052 BRASERO_MEDIA_LOG ("Device does not respond");
3053
3054 brasero_device_handle_close (handle);
3055 goto end;
3056 }
3057
3058 g_get_current_time (&wait_time);
3059 g_time_val_add (&wait_time, 2000000);
3060
3061 g_mutex_lock (priv->mutex);
3062 g_cond_timed_wait (priv->cond_probe,
3063 priv->mutex,
3064 &wait_time);
3065 g_mutex_unlock (priv->mutex);
3066
3067 if (priv->probe_cancelled) {
3068 BRASERO_MEDIA_LOG ("Device probing cancelled");
3069
3070 brasero_device_handle_close (handle);
3071 goto end;
3072 }
3073 }
3074
3075 BRASERO_MEDIA_LOG ("Device ready");
3076
3077 brasero_medium_init_real (BRASERO_MEDIUM (self), handle);
3078 brasero_device_handle_close (handle);
3079
3080 end:
3081
3082 g_mutex_lock (priv->mutex);
3083
3084 priv->probe = NULL;
3085 if (!priv->probe_cancelled)
3086 priv->probe_id = g_idle_add (brasero_medium_probed, self);
3087
3088 g_cond_broadcast (priv->cond);
3089 g_mutex_unlock (priv->mutex);
3090
3091 g_thread_exit (0);
3092
3093 return NULL;
3094 }
3095
3096 static void
brasero_medium_probe(BraseroMedium * self)3097 brasero_medium_probe (BraseroMedium *self)
3098 {
3099 BraseroMediumPrivate *priv;
3100
3101 priv = BRASERO_MEDIUM_PRIVATE (self);
3102
3103 /* NOTE: why a thread? Because in case of a damaged medium, brasero can
3104 * block on some functions until timeout and if we do this in the main
3105 * thread then our whole UI blocks. This medium won't be exported by the
3106 * BraseroDrive that exported until it returns PROBED signal.
3107 * One (good) side effect is that it also improves start time. */
3108 g_mutex_lock (priv->mutex);
3109 priv->probe = g_thread_create (brasero_medium_probe_thread,
3110 self,
3111 FALSE,
3112 NULL);
3113 g_mutex_unlock (priv->mutex);
3114 }
3115
3116 static void
brasero_medium_init_file(BraseroMedium * self)3117 brasero_medium_init_file (BraseroMedium *self)
3118 {
3119 BraseroMediumPrivate *priv;
3120
3121 priv = BRASERO_MEDIUM_PRIVATE (self);
3122
3123 priv->info = BRASERO_MEDIUM_FILE;
3124 priv->type = types [0];
3125 }
3126
3127 static void
brasero_medium_init(BraseroMedium * object)3128 brasero_medium_init (BraseroMedium *object)
3129 {
3130 BraseroMediumPrivate *priv;
3131
3132 priv = BRASERO_MEDIUM_PRIVATE (object);
3133 priv->next_wr_add = -1;
3134
3135 priv->mutex = g_mutex_new ();
3136 priv->cond = g_cond_new ();
3137 priv->cond_probe = g_cond_new ();
3138
3139 /* we can't do anything here since properties haven't been set yet */
3140 }
3141
3142 static void
brasero_medium_finalize(GObject * object)3143 brasero_medium_finalize (GObject *object)
3144 {
3145 BraseroMediumPrivate *priv;
3146
3147 priv = BRASERO_MEDIUM_PRIVATE (object);
3148
3149 BRASERO_MEDIA_LOG ("Finalizing Medium object");
3150
3151 g_mutex_lock (priv->mutex);
3152 if (priv->probe) {
3153 /* This to signal that we are cancelling */
3154 priv->probe_cancelled = TRUE;
3155
3156 /* This is to wake up the thread if it
3157 * was asleep waiting to retry to get
3158 * hold of a handle to probe the drive */
3159 g_cond_signal (priv->cond_probe);
3160
3161 /* Wait for the end of the thread */
3162 g_cond_wait (priv->cond, priv->mutex);
3163 }
3164 g_mutex_unlock (priv->mutex);
3165
3166 if (priv->probe_id) {
3167 g_source_remove (priv->probe_id);
3168 priv->probe_id = 0;
3169 }
3170
3171 if (priv->mutex) {
3172 g_mutex_free (priv->mutex);
3173 priv->mutex = NULL;
3174 }
3175
3176 if (priv->cond) {
3177 g_cond_free (priv->cond);
3178 priv->cond = NULL;
3179 }
3180
3181 if (priv->cond_probe) {
3182 g_cond_free (priv->cond_probe);
3183 priv->cond_probe = NULL;
3184 }
3185
3186 if (priv->id) {
3187 g_free (priv->id);
3188 priv->id = NULL;
3189 }
3190
3191 if (priv->CD_TEXT_title) {
3192 g_free (priv->CD_TEXT_title);
3193 priv->CD_TEXT_title = NULL;
3194 }
3195
3196 g_free (priv->rd_speeds);
3197 priv->rd_speeds = NULL;
3198
3199 g_free (priv->wr_speeds);
3200 priv->wr_speeds = NULL;
3201
3202 g_slist_foreach (priv->tracks, (GFunc) g_free, NULL);
3203 g_slist_free (priv->tracks);
3204 priv->tracks = NULL;
3205
3206 priv->drive = NULL;
3207
3208 G_OBJECT_CLASS (parent_class)->finalize (object);
3209 }
3210
3211 static void
brasero_medium_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)3212 brasero_medium_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
3213 {
3214 BraseroMediumPrivate *priv;
3215
3216 g_return_if_fail (BRASERO_IS_MEDIUM (object));
3217
3218 priv = BRASERO_MEDIUM_PRIVATE (object);
3219
3220 switch (prop_id)
3221 {
3222 case PROP_DRIVE:
3223 /* we don't ref the drive here as it would create a circular
3224 * dependency where the drive would hold a reference on the
3225 * medium and the medium on the drive */
3226 priv->drive = g_value_get_object (value);
3227
3228 if (brasero_drive_is_fake (priv->drive)) {
3229 brasero_medium_init_file (BRASERO_MEDIUM (object));
3230 break;
3231 }
3232
3233 brasero_medium_probe (BRASERO_MEDIUM (object));
3234 break;
3235 default:
3236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3237 break;
3238 }
3239 }
3240
3241 static void
brasero_medium_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)3242 brasero_medium_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
3243 {
3244 BraseroMediumPrivate *priv;
3245
3246 g_return_if_fail (BRASERO_IS_MEDIUM (object));
3247
3248 priv = BRASERO_MEDIUM_PRIVATE (object);
3249
3250 switch (prop_id)
3251 {
3252 case PROP_DRIVE:
3253 g_value_set_object (value, priv->drive);
3254 break;
3255 default:
3256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3257 break;
3258 }
3259 }
3260
3261 static void
brasero_medium_class_init(BraseroMediumClass * klass)3262 brasero_medium_class_init (BraseroMediumClass *klass)
3263 {
3264 GObjectClass* object_class = G_OBJECT_CLASS (klass);
3265 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
3266
3267 g_type_class_add_private (klass, sizeof (BraseroMediumPrivate));
3268
3269 object_class->finalize = brasero_medium_finalize;
3270 object_class->set_property = brasero_medium_set_property;
3271 object_class->get_property = brasero_medium_get_property;
3272
3273 /**
3274 * BraseroMedium::probed:
3275 * @medium: the object which received the signal
3276 *
3277 * This signal gets emitted when the medium inside the drive has been
3278 * fully probed. This is mostly for internal use.
3279 *
3280 */
3281 medium_signals[PROBED] =
3282 g_signal_new ("probed",
3283 G_OBJECT_CLASS_TYPE (klass),
3284 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
3285 0,
3286 NULL, NULL,
3287 g_cclosure_marshal_VOID__VOID,
3288 G_TYPE_NONE, 0,
3289 G_TYPE_NONE);
3290
3291 g_object_class_install_property (object_class,
3292 PROP_DRIVE,
3293 g_param_spec_object ("drive",
3294 "Drive",
3295 "Drive in which medium is inserted",
3296 BRASERO_TYPE_DRIVE,
3297 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3298 }
3299
3300 /**
3301 * brasero_medium_can_be_written:
3302 * @medium: #BraseroMedium
3303 *
3304 * Gets whether the medium can be written. It also checks that the medium can
3305 * write the medium.
3306 *
3307 * Return value: a #gboolean. TRUE if the medium can be rewritten, FALSE otherwise.
3308 *
3309 **/
3310 gboolean
brasero_medium_can_be_written(BraseroMedium * medium)3311 brasero_medium_can_be_written (BraseroMedium *medium)
3312 {
3313 BraseroMediumPrivate *priv;
3314
3315 g_return_val_if_fail (medium != NULL, FALSE);
3316 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3317
3318 priv = BRASERO_MEDIUM_PRIVATE (medium);
3319
3320 return brasero_drive_can_write_media (priv->drive, priv->info);
3321 }
3322
3323 /**
3324 * brasero_medium_can_be_rewritten:
3325 * @medium: #BraseroMedium
3326 *
3327 * Gets whether the medium can be rewritten. Note: it also checks that the drive
3328 * can rewrite the medium type.
3329 *
3330 * Return value: a #gboolean. TRUE if the medium can be rewritten, FALSE otherwise.
3331 *
3332 **/
3333 gboolean
brasero_medium_can_be_rewritten(BraseroMedium * medium)3334 brasero_medium_can_be_rewritten (BraseroMedium *medium)
3335 {
3336 BraseroMediumPrivate *priv;
3337
3338 g_return_val_if_fail (medium != NULL, FALSE);
3339 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3340
3341 priv = BRASERO_MEDIUM_PRIVATE (medium);
3342
3343 if (!(priv->info & BRASERO_MEDIUM_REWRITABLE)
3344 || (priv->info & BRASERO_MEDIUM_FILE))
3345 return FALSE;
3346
3347 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_CDRW)
3348 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW))
3349 return priv->blank_command != 0;
3350
3351 if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)
3352 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS)
3353 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS_DL)
3354 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVD_RAM)
3355 || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_BDRE))
3356 return TRUE;
3357
3358 return FALSE;
3359 }
3360 /**
3361 * brasero_medium_can_use_sao:
3362 * @medium: #BraseroMedium
3363 *
3364 * Gets whether the medium supports SAO.
3365 *
3366 * Since 2.29
3367 *
3368 * Return value: a #gboolean. TRUE if the medium can use SAO write mode , FALSE otherwise.
3369 *
3370 **/
3371 gboolean
brasero_medium_can_use_sao(BraseroMedium * medium)3372 brasero_medium_can_use_sao (BraseroMedium *medium)
3373 {
3374 BraseroMediumPrivate *priv;
3375
3376 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3377
3378 priv = BRASERO_MEDIUM_PRIVATE (medium);
3379 return priv->sao;
3380 }
3381
3382 /**
3383 * brasero_medium_can_use_tao:
3384 * @medium: #BraseroMedium
3385 *
3386 * Gets whether the medium supports TAO.
3387 *
3388 * Since 2.29
3389 *
3390 * Return value: a #gboolean. TRUE if the medium can use TAO write mode, FALSE otherwise.
3391 *
3392 **/
3393 gboolean
brasero_medium_can_use_tao(BraseroMedium * medium)3394 brasero_medium_can_use_tao (BraseroMedium *medium)
3395 {
3396 BraseroMediumPrivate *priv;
3397
3398 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3399
3400 priv = BRASERO_MEDIUM_PRIVATE (medium);
3401 return priv->tao;
3402 }
3403
3404 /**
3405 * brasero_medium_can_use_dummy_for_sao:
3406 * @medium: #BraseroMedium
3407 *
3408 * Gets whether the medium supports doing a test write with SAO on.
3409 *
3410 * Return value: a #gboolean. TRUE if the medium can use SAO write mode during a test write, FALSE otherwise.
3411 *
3412 **/
3413 gboolean
brasero_medium_can_use_dummy_for_sao(BraseroMedium * medium)3414 brasero_medium_can_use_dummy_for_sao (BraseroMedium *medium)
3415 {
3416 BraseroMediumPrivate *priv;
3417
3418 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3419
3420 priv = BRASERO_MEDIUM_PRIVATE (medium);
3421 return priv->dummy_sao;
3422 }
3423
3424 /**
3425 * brasero_medium_can_use_dummy_for_tao:
3426 * @medium: #BraseroMedium
3427 *
3428 * Gets whether the medium supports doing a test write with TAO on.
3429 *
3430 * Return value: a #gboolean. TRUE if the medium can use TAO write mode during a test write, FALSE otherwise.
3431 *
3432 **/
3433 gboolean
brasero_medium_can_use_dummy_for_tao(BraseroMedium * medium)3434 brasero_medium_can_use_dummy_for_tao (BraseroMedium *medium)
3435 {
3436 BraseroMediumPrivate *priv;
3437
3438 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3439
3440 priv = BRASERO_MEDIUM_PRIVATE (medium);
3441 return priv->dummy_tao;
3442 }
3443
3444 /**
3445 * brasero_medium_can_use_burnfree:
3446 * @medium: #BraseroMedium
3447 *
3448 * Gets whether the medium supports any burnfree technology.
3449 *
3450 * Return value: a #gboolean. TRUE if the medium can use any burnfree technology, FALSE otherwise.
3451 *
3452 **/
3453 gboolean
brasero_medium_can_use_burnfree(BraseroMedium * medium)3454 brasero_medium_can_use_burnfree (BraseroMedium *medium)
3455 {
3456 BraseroMediumPrivate *priv;
3457
3458 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), FALSE);
3459
3460 priv = BRASERO_MEDIUM_PRIVATE (medium);
3461 return priv->burnfree;
3462 }
3463
3464 /**
3465 * brasero_medium_get_drive:
3466 * @medium: #BraseroMedium
3467 *
3468 * Gets the #BraseroDrive in which the medium is inserted.
3469 *
3470 * Return value: (transfer none): a #BraseroDrive. No need to unref after use.
3471 *
3472 **/
3473 BraseroDrive *
brasero_medium_get_drive(BraseroMedium * medium)3474 brasero_medium_get_drive (BraseroMedium *medium)
3475 {
3476 BraseroMediumPrivate *priv;
3477
3478 if (!medium)
3479 return NULL;
3480
3481 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), NULL);
3482
3483 priv = BRASERO_MEDIUM_PRIVATE (medium);
3484 return priv->drive;
3485 }
3486
3487 /**
3488 * brasero_medium_get_CD_TEXT_title:
3489 * @medium: #BraseroMedium
3490 *
3491 * Gets the CD-TEXT title for @Medium.
3492 *
3493 * Return value: a #gchar *.
3494 *
3495 **/
3496 const gchar *
brasero_medium_get_CD_TEXT_title(BraseroMedium * medium)3497 brasero_medium_get_CD_TEXT_title (BraseroMedium *medium)
3498 {
3499 BraseroMediumPrivate *priv;
3500
3501 g_return_val_if_fail (medium != NULL, NULL);
3502 g_return_val_if_fail (BRASERO_IS_MEDIUM (medium), NULL);
3503
3504 priv = BRASERO_MEDIUM_PRIVATE (medium);
3505 return priv->CD_TEXT_title;
3506
3507 }
3508
3509 GType
brasero_medium_get_type(void)3510 brasero_medium_get_type (void)
3511 {
3512 static GType our_type = 0;
3513
3514 if (our_type == 0)
3515 {
3516 static const GTypeInfo our_info =
3517 {
3518 sizeof (BraseroMediumClass), /* class_size */
3519 (GBaseInitFunc) NULL, /* base_init */
3520 (GBaseFinalizeFunc) NULL, /* base_finalize */
3521 (GClassInitFunc) brasero_medium_class_init, /* class_init */
3522 (GClassFinalizeFunc) NULL, /* class_finalize */
3523 NULL /* class_data */,
3524 sizeof (BraseroMedium), /* instance_size */
3525 0, /* n_preallocs */
3526 (GInstanceInitFunc) brasero_medium_init, /* instance_init */
3527 NULL /* value_table */
3528 };
3529
3530 our_type = g_type_register_static (G_TYPE_OBJECT, "BraseroMedium",
3531 &our_info, 0);
3532 }
3533
3534 return our_type;
3535 }
3536