1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-burn
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5 *
6 * Libbrasero-burn 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-burn authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-burn. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-burn 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-burn 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 <math.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42
43 #include <glib.h>
44 #include <glib-object.h>
45 #include <glib/gi18n-lib.h>
46 #include <glib/gstdio.h>
47
48 #include "brasero-burn.h"
49
50 #include "libbrasero-marshal.h"
51 #include "burn-basics.h"
52 #include "burn-debug.h"
53 #include "burn-dbus.h"
54 #include "burn-task-ctx.h"
55 #include "burn-task.h"
56 #include "brasero-caps-burn.h"
57
58 #include "brasero-drive-priv.h"
59
60 #include "brasero-volume.h"
61 #include "brasero-drive.h"
62
63 #include "brasero-tags.h"
64 #include "brasero-track.h"
65 #include "brasero-session.h"
66 #include "brasero-track-image.h"
67 #include "brasero-track-disc.h"
68 #include "brasero-session-helper.h"
69
70 G_DEFINE_TYPE (BraseroBurn, brasero_burn, G_TYPE_OBJECT);
71
72 typedef struct _BraseroBurnPrivate BraseroBurnPrivate;
73 struct _BraseroBurnPrivate {
74 BraseroBurnCaps *caps;
75 BraseroBurnSession *session;
76
77 GMainLoop *sleep_loop;
78 guint timeout_id;
79
80 guint tasks_done;
81 guint task_nb;
82 BraseroTask *task;
83
84 BraseroDrive *src;
85 BraseroDrive *dest;
86
87 gint appcookie;
88
89 guint64 session_start;
90 guint64 session_end;
91
92 guint mounted_by_us:1;
93 };
94
95 #define BRASERO_BURN_NOT_SUPPORTED_LOG(burn) \
96 { \
97 brasero_burn_log (burn, \
98 "unsupported operation (in %s at %s)", \
99 G_STRFUNC, \
100 G_STRLOC); \
101 return BRASERO_BURN_NOT_SUPPORTED; \
102 }
103
104 #define BRASERO_BURN_NOT_READY_LOG(burn) \
105 { \
106 brasero_burn_log (burn, \
107 "not ready to operate (in %s at %s)", \
108 G_STRFUNC, \
109 G_STRLOC); \
110 return BRASERO_BURN_NOT_READY; \
111 }
112
113 #define BRASERO_BURN_DEBUG(burn, message, ...) \
114 { \
115 gchar *format; \
116 BRASERO_BURN_LOG (message, ##__VA_ARGS__); \
117 format = g_strdup_printf ("%s (%s %s)", \
118 message, \
119 G_STRFUNC, \
120 G_STRLOC); \
121 brasero_burn_log (burn, \
122 format, \
123 ##__VA_ARGS__); \
124 g_free (format); \
125 }
126
127 typedef enum {
128 ASK_DISABLE_JOLIET_SIGNAL,
129 WARN_DATA_LOSS_SIGNAL,
130 WARN_PREVIOUS_SESSION_LOSS_SIGNAL,
131 WARN_AUDIO_TO_APPENDABLE_SIGNAL,
132 WARN_REWRITABLE_SIGNAL,
133 INSERT_MEDIA_REQUEST_SIGNAL,
134 LOCATION_REQUEST_SIGNAL,
135 PROGRESS_CHANGED_SIGNAL,
136 ACTION_CHANGED_SIGNAL,
137 DUMMY_SUCCESS_SIGNAL,
138 EJECT_FAILURE_SIGNAL,
139 BLANK_FAILURE_SIGNAL,
140 INSTALL_MISSING_SIGNAL,
141 LAST_SIGNAL
142 } BraseroBurnSignalType;
143
144 static guint brasero_burn_signals [LAST_SIGNAL] = { 0 };
145
146 #define BRASERO_BURN_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_BURN, BraseroBurnPrivate))
147
148 #define MAX_EJECT_ATTEMPTS 5
149 #define MAX_MOUNT_ATTEMPTS 40
150
151 #define MOUNT_TIMEOUT 500
152
153 static GObjectClass *parent_class = NULL;
154
155 static void
brasero_burn_powermanagement(BraseroBurn * self,gboolean wake)156 brasero_burn_powermanagement (BraseroBurn *self,
157 gboolean wake)
158 {
159 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (self);
160
161 if (wake)
162 priv->appcookie = brasero_inhibit_suspend (_("Burning CD/DVD"));
163 else
164 brasero_uninhibit_suspend (priv->appcookie);
165 }
166
167 /**
168 * brasero_burn_new:
169 *
170 * Creates a new #BraseroBurn object.
171 *
172 * Return value: a #BraseroBurn object.
173 **/
174
175 BraseroBurn *
brasero_burn_new()176 brasero_burn_new ()
177 {
178 return g_object_new (BRASERO_TYPE_BURN, NULL);
179 }
180
181 static void
brasero_burn_log(BraseroBurn * burn,const gchar * format,...)182 brasero_burn_log (BraseroBurn *burn,
183 const gchar *format,
184 ...)
185 {
186 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
187 va_list arg_list;
188
189 va_start (arg_list, format);
190 brasero_burn_session_logv (priv->session, format, arg_list);
191 va_end (arg_list);
192 }
193
194 static BraseroBurnResult
brasero_burn_emit_signal(BraseroBurn * burn,guint signal,BraseroBurnResult default_answer)195 brasero_burn_emit_signal (BraseroBurn *burn,
196 guint signal,
197 BraseroBurnResult default_answer)
198 {
199 GValue instance_and_params;
200 GValue return_value;
201
202 instance_and_params.g_type = 0;
203 g_value_init (&instance_and_params, G_TYPE_FROM_INSTANCE (burn));
204 g_value_set_instance (&instance_and_params, burn);
205
206 return_value.g_type = 0;
207 g_value_init (&return_value, G_TYPE_INT);
208 g_value_set_int (&return_value, default_answer);
209
210 g_signal_emitv (&instance_and_params,
211 brasero_burn_signals [signal],
212 0,
213 &return_value);
214
215 g_value_unset (&instance_and_params);
216
217 return g_value_get_int (&return_value);
218 }
219
220 static void
brasero_burn_action_changed_real(BraseroBurn * burn,BraseroBurnAction action)221 brasero_burn_action_changed_real (BraseroBurn *burn,
222 BraseroBurnAction action)
223 {
224 g_signal_emit (burn,
225 brasero_burn_signals [ACTION_CHANGED_SIGNAL],
226 0,
227 action);
228
229 if (action == BRASERO_BURN_ACTION_FINISHED)
230 g_signal_emit (burn,
231 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
232 0,
233 1.0,
234 1.0,
235 -1L);
236 else if (action == BRASERO_BURN_ACTION_EJECTING)
237 g_signal_emit (burn,
238 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
239 0,
240 -1.0,
241 -1.0,
242 -1L);
243 }
244
245 static gboolean
brasero_burn_wakeup(BraseroBurn * burn)246 brasero_burn_wakeup (BraseroBurn *burn)
247 {
248 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
249
250 if (priv->sleep_loop)
251 g_main_loop_quit (priv->sleep_loop);
252
253 priv->timeout_id = 0;
254 return FALSE;
255 }
256
257 static BraseroBurnResult
brasero_burn_sleep(BraseroBurn * burn,gint msec)258 brasero_burn_sleep (BraseroBurn *burn, gint msec)
259 {
260 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
261 GMainLoop *loop;
262
263 priv->sleep_loop = g_main_loop_new (NULL, FALSE);
264 priv->timeout_id = g_timeout_add (msec,
265 (GSourceFunc) brasero_burn_wakeup,
266 burn);
267
268 /* Keep a reference to the loop in case we are cancelled to destroy it */
269 loop = priv->sleep_loop;
270 g_main_loop_run (loop);
271
272 if (priv->timeout_id) {
273 g_source_remove (priv->timeout_id);
274 priv->timeout_id = 0;
275 }
276
277 g_main_loop_unref (loop);
278 if (priv->sleep_loop) {
279 priv->sleep_loop = NULL;
280 return BRASERO_BURN_OK;
281 }
282
283 /* if sleep_loop = NULL => We've been cancelled */
284 return BRASERO_BURN_CANCEL;
285 }
286
287 static BraseroBurnResult
brasero_burn_reprobe(BraseroBurn * burn)288 brasero_burn_reprobe (BraseroBurn *burn)
289 {
290 BraseroBurnPrivate *priv;
291 BraseroBurnResult result = BRASERO_BURN_OK;
292
293 priv = BRASERO_BURN_PRIVATE (burn);
294
295 BRASERO_BURN_LOG ("Reprobing for medium");
296
297 /* reprobe the medium and wait for it to be probed */
298 brasero_drive_reprobe (priv->dest);
299 while (brasero_drive_probing (priv->dest)) {
300 result = brasero_burn_sleep (burn, 250);
301 if (result != BRASERO_BURN_OK)
302 return result;
303 }
304
305 return result;
306 }
307
308 static BraseroBurnResult
brasero_burn_unmount(BraseroBurn * self,BraseroMedium * medium,GError ** error)309 brasero_burn_unmount (BraseroBurn *self,
310 BraseroMedium *medium,
311 GError **error)
312 {
313 guint counter = 0;
314
315 if (!medium)
316 return BRASERO_BURN_OK;
317
318 /* Retry several times, since sometimes the drives are really busy */
319 while (brasero_volume_is_mounted (BRASERO_VOLUME (medium))) {
320 GError *ret_error;
321 BraseroBurnResult result;
322
323 counter ++;
324 if (counter > MAX_EJECT_ATTEMPTS) {
325 BRASERO_BURN_LOG ("Max attempts reached at unmounting");
326 if (error && !(*error))
327 g_set_error (error,
328 BRASERO_BURN_ERROR,
329 BRASERO_BURN_ERROR_DRIVE_BUSY,
330 "%s. %s",
331 _("The drive is busy"),
332 _("Make sure another application is not using it"));
333 return BRASERO_BURN_ERR;
334 }
335
336 BRASERO_BURN_LOG ("Retrying unmounting");
337
338 ret_error = NULL;
339 brasero_volume_umount (BRASERO_VOLUME (medium), TRUE, NULL);
340
341 if (ret_error) {
342 BRASERO_BURN_LOG ("Ejection error: %s", ret_error->message);
343 g_error_free (ret_error);
344 }
345
346 result = brasero_burn_sleep (self, 500);
347 if (result != BRASERO_BURN_OK)
348 return result;
349 }
350
351 return BRASERO_BURN_OK;
352 }
353
354 static BraseroBurnResult
brasero_burn_emit_eject_failure_signal(BraseroBurn * burn,BraseroDrive * drive)355 brasero_burn_emit_eject_failure_signal (BraseroBurn *burn,
356 BraseroDrive *drive)
357 {
358 GValue instance_and_params [4];
359 GValue return_value;
360
361 instance_and_params [0].g_type = 0;
362 g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (burn));
363 g_value_set_instance (instance_and_params, burn);
364
365 instance_and_params [1].g_type = 0;
366 g_value_init (instance_and_params + 1, G_TYPE_FROM_INSTANCE (drive));
367 g_value_set_instance (instance_and_params + 1, drive);
368
369 return_value.g_type = 0;
370 g_value_init (&return_value, G_TYPE_INT);
371 g_value_set_int (&return_value, BRASERO_BURN_CANCEL);
372
373 g_signal_emitv (instance_and_params,
374 brasero_burn_signals [EJECT_FAILURE_SIGNAL],
375 0,
376 &return_value);
377
378 g_value_unset (instance_and_params);
379
380 return g_value_get_int (&return_value);
381 }
382
383 static BraseroBurnResult
brasero_burn_eject(BraseroBurn * self,BraseroDrive * drive,GError ** error)384 brasero_burn_eject (BraseroBurn *self,
385 BraseroDrive *drive,
386 GError **error)
387 {
388 guint counter = 0;
389 BraseroMedium *medium;
390 BraseroBurnResult result;
391
392 BRASERO_BURN_LOG ("Ejecting drive/medium");
393
394 /* Unmount, ... */
395 medium = brasero_drive_get_medium (drive);
396 result = brasero_burn_unmount (self, medium, error);
397 if (result != BRASERO_BURN_OK)
398 return result;
399
400 /* Release lock, ... */
401 if (brasero_drive_is_locked (drive, NULL)) {
402 if (!brasero_drive_unlock (drive)) {
403 gchar *name;
404
405 name = brasero_drive_get_display_name (drive);
406 g_set_error (error,
407 BRASERO_BURN_ERROR,
408 BRASERO_BURN_ERROR_GENERAL,
409 _("\"%s\" cannot be unlocked"),
410 name);
411 g_free (name);
412 return BRASERO_BURN_ERR;
413 }
414 }
415
416 /* Retry several times, since sometimes the drives are really busy */
417 while (brasero_drive_get_medium (drive) || brasero_drive_probing (drive)) {
418 GError *ret_error;
419
420 /* Don't interrupt a probe */
421 if (brasero_drive_probing (drive)) {
422 result = brasero_burn_sleep (self, 500);
423 if (result != BRASERO_BURN_OK)
424 return result;
425
426 continue;
427 }
428
429 counter ++;
430 if (counter == 1)
431 brasero_burn_action_changed_real (self, BRASERO_BURN_ACTION_EJECTING);
432
433 if (counter > MAX_EJECT_ATTEMPTS) {
434 BRASERO_BURN_LOG ("Max attempts reached at ejecting");
435
436 result = brasero_burn_emit_eject_failure_signal (self, drive);
437 if (result != BRASERO_BURN_OK)
438 return result;
439
440 continue;
441 }
442
443 BRASERO_BURN_LOG ("Retrying ejection");
444 ret_error = NULL;
445 brasero_drive_eject (drive, TRUE, &ret_error);
446
447 if (ret_error) {
448 BRASERO_BURN_LOG ("Ejection error: %s", ret_error->message);
449 g_error_free (ret_error);
450 }
451
452 result = brasero_burn_sleep (self, 500);
453 if (result != BRASERO_BURN_OK)
454 return result;
455 }
456
457 return BRASERO_BURN_OK;
458 }
459
460 static BraseroBurnResult
brasero_burn_ask_for_media(BraseroBurn * burn,BraseroDrive * drive,BraseroBurnError error_type,BraseroMedia required_media,GError ** error)461 brasero_burn_ask_for_media (BraseroBurn *burn,
462 BraseroDrive *drive,
463 BraseroBurnError error_type,
464 BraseroMedia required_media,
465 GError **error)
466 {
467 GValue instance_and_params [4];
468 GValue return_value;
469
470 instance_and_params [0].g_type = 0;
471 g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (burn));
472 g_value_set_instance (instance_and_params, burn);
473
474 instance_and_params [1].g_type = 0;
475 g_value_init (instance_and_params + 1, G_TYPE_FROM_INSTANCE (drive));
476 g_value_set_instance (instance_and_params + 1, drive);
477
478 instance_and_params [2].g_type = 0;
479 g_value_init (instance_and_params + 2, G_TYPE_INT);
480 g_value_set_int (instance_and_params + 2, error_type);
481
482 instance_and_params [3].g_type = 0;
483 g_value_init (instance_and_params + 3, G_TYPE_INT);
484 g_value_set_int (instance_and_params + 3, required_media);
485
486 return_value.g_type = 0;
487 g_value_init (&return_value, G_TYPE_INT);
488 g_value_set_int (&return_value, BRASERO_BURN_CANCEL);
489
490 g_signal_emitv (instance_and_params,
491 brasero_burn_signals [INSERT_MEDIA_REQUEST_SIGNAL],
492 0,
493 &return_value);
494
495 g_value_unset (instance_and_params);
496 g_value_unset (instance_and_params + 1);
497
498 return g_value_get_int (&return_value);
499 }
500
501 static BraseroBurnResult
brasero_burn_ask_for_src_media(BraseroBurn * burn,BraseroBurnError error_type,BraseroMedia required_media,GError ** error)502 brasero_burn_ask_for_src_media (BraseroBurn *burn,
503 BraseroBurnError error_type,
504 BraseroMedia required_media,
505 GError **error)
506 {
507 BraseroMedium *medium;
508 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
509
510 medium = brasero_drive_get_medium (priv->src);
511 if (brasero_medium_get_status (medium) != BRASERO_MEDIUM_NONE
512 || brasero_drive_probing (priv->src)) {
513 BraseroBurnResult result;
514 result = brasero_burn_eject (burn, priv->src, error);
515 if (result != BRASERO_BURN_OK)
516 return result;
517 }
518
519 return brasero_burn_ask_for_media (burn,
520 priv->src,
521 error_type,
522 required_media,
523 error);
524 }
525
526 static BraseroBurnResult
brasero_burn_ask_for_dest_media(BraseroBurn * burn,BraseroBurnError error_type,BraseroMedia required_media,GError ** error)527 brasero_burn_ask_for_dest_media (BraseroBurn *burn,
528 BraseroBurnError error_type,
529 BraseroMedia required_media,
530 GError **error)
531 {
532 BraseroDrive *drive;
533 BraseroMedium *medium;
534 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
535
536 /* Since in some cases (like when we reload
537 * a medium after a copy), the destination
538 * medium may not be locked yet we use
539 * separate variable drive. */
540 if (!priv->dest) {
541 drive = brasero_burn_session_get_burner (priv->session);
542 if (!drive) {
543 g_set_error (error,
544 BRASERO_BURN_ERROR,
545 BRASERO_BURN_ERROR_OUTPUT_NONE,
546 "%s", _("No burner specified"));
547 return BRASERO_BURN_ERR;
548 }
549 }
550 else
551 drive = priv->dest;
552
553 medium = brasero_drive_get_medium (drive);
554 if (brasero_medium_get_status (medium) != BRASERO_MEDIUM_NONE
555 || brasero_drive_probing (drive)) {
556 BraseroBurnResult result;
557
558 result = brasero_burn_eject (burn, drive, error);
559 if (result != BRASERO_BURN_OK)
560 return result;
561 }
562
563 return brasero_burn_ask_for_media (burn,
564 drive,
565 error_type,
566 required_media,
567 error);
568 }
569
570 static BraseroBurnResult
brasero_burn_lock_src_media(BraseroBurn * burn,GError ** error)571 brasero_burn_lock_src_media (BraseroBurn *burn,
572 GError **error)
573 {
574 gchar *failure = NULL;
575 BraseroMedia media;
576 BraseroMedium *medium;
577 BraseroBurnResult result;
578 BraseroBurnError error_type;
579 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
580
581 priv->src = brasero_burn_session_get_src_drive (priv->session);
582 if (!priv->src) {
583 g_set_error (error,
584 BRASERO_BURN_ERROR,
585 BRASERO_BURN_ERROR_GENERAL,
586 "%s", _("No source drive specified"));
587 return BRASERO_BURN_ERR;
588 }
589
590
591 again:
592
593 while (brasero_drive_probing (priv->src)) {
594 result = brasero_burn_sleep (burn, 500);
595 if (result != BRASERO_BURN_OK)
596 return result;
597 }
598
599 medium = brasero_drive_get_medium (priv->src);
600 if (brasero_volume_is_mounted (BRASERO_VOLUME (medium))) {
601 if (!brasero_volume_umount (BRASERO_VOLUME (medium), TRUE, NULL))
602 g_warning ("Couldn't unmount volume in drive: %s",
603 brasero_drive_get_device (priv->src));
604 }
605
606 /* NOTE: we used to unmount the media before now we shouldn't need that
607 * get any information from the drive */
608 media = brasero_medium_get_status (medium);
609 if (media == BRASERO_MEDIUM_NONE)
610 error_type = BRASERO_BURN_ERROR_MEDIUM_NONE;
611 else if (media == BRASERO_MEDIUM_BUSY)
612 error_type = BRASERO_BURN_ERROR_DRIVE_BUSY;
613 else if (media == BRASERO_MEDIUM_UNSUPPORTED)
614 error_type = BRASERO_BURN_ERROR_MEDIUM_INVALID;
615 else if (media & BRASERO_MEDIUM_BLANK)
616 error_type = BRASERO_BURN_ERROR_MEDIUM_NO_DATA;
617 else
618 error_type = BRASERO_BURN_ERROR_NONE;
619
620 if (error_type != BRASERO_BURN_ERROR_NONE) {
621 result = brasero_burn_ask_for_src_media (burn,
622 BRASERO_BURN_ERROR_MEDIUM_NO_DATA,
623 error_type,
624 error);
625 if (result != BRASERO_BURN_OK)
626 return result;
627
628 goto again;
629 }
630
631 if (!brasero_drive_is_locked (priv->src, NULL)
632 && !brasero_drive_lock (priv->src, _("Ongoing copying process"), &failure)) {
633 g_set_error (error,
634 BRASERO_BURN_ERROR,
635 BRASERO_BURN_ERROR_GENERAL,
636 _("The drive cannot be locked (%s)"),
637 failure);
638 return BRASERO_BURN_ERR;
639 }
640
641 return BRASERO_BURN_OK;
642 }
643
644 static BraseroBurnResult
brasero_burn_reload_src_media(BraseroBurn * burn,BraseroBurnError error_code,GError ** error)645 brasero_burn_reload_src_media (BraseroBurn *burn,
646 BraseroBurnError error_code,
647 GError **error)
648 {
649 BraseroBurnResult result;
650
651 result = brasero_burn_ask_for_src_media (burn,
652 error_code,
653 BRASERO_MEDIUM_HAS_DATA,
654 error);
655 if (result != BRASERO_BURN_OK)
656 return result;
657
658 result = brasero_burn_lock_src_media (burn, error);
659 return result;
660 }
661
662 static BraseroBurnResult
brasero_burn_lock_rewritable_media(BraseroBurn * burn,GError ** error)663 brasero_burn_lock_rewritable_media (BraseroBurn *burn,
664 GError **error)
665 {
666 gchar *failure;
667 BraseroMedia media;
668 BraseroMedium *medium;
669 BraseroBurnResult result;
670 BraseroBurnError error_type;
671 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
672
673 priv->dest = brasero_burn_session_get_burner (priv->session);
674 if (!priv->dest) {
675 g_set_error (error,
676 BRASERO_BURN_ERROR,
677 BRASERO_BURN_ERROR_OUTPUT_NONE,
678 "%s", _("No burner specified"));
679 return BRASERO_BURN_NOT_SUPPORTED;
680 }
681
682 again:
683
684 while (brasero_drive_probing (priv->dest)) {
685 result = brasero_burn_sleep (burn, 500);
686 if (result != BRASERO_BURN_OK)
687 return result;
688 }
689
690 medium = brasero_drive_get_medium (priv->dest);
691 if (!brasero_medium_can_be_rewritten (medium)) {
692 g_set_error (error,
693 BRASERO_BURN_ERROR,
694 BRASERO_BURN_ERROR_MEDIUM_NOT_REWRITABLE,
695 "%s", _("The drive has no rewriting capabilities"));
696 return BRASERO_BURN_NOT_SUPPORTED;
697 }
698
699 if (brasero_volume_is_mounted (BRASERO_VOLUME (medium))) {
700 if (!brasero_volume_umount (BRASERO_VOLUME (medium), TRUE, NULL))
701 g_warning ("Couldn't unmount volume in drive: %s",
702 brasero_drive_get_device (priv->dest));
703 }
704
705 media = brasero_medium_get_status (medium);
706 if (media == BRASERO_MEDIUM_NONE)
707 error_type = BRASERO_BURN_ERROR_MEDIUM_NONE;
708 else if (media == BRASERO_MEDIUM_BUSY)
709 error_type = BRASERO_BURN_ERROR_DRIVE_BUSY;
710 else if (media == BRASERO_MEDIUM_UNSUPPORTED)
711 error_type = BRASERO_BURN_ERROR_MEDIUM_INVALID;
712 else if (!(media & BRASERO_MEDIUM_REWRITABLE))
713 error_type = BRASERO_BURN_ERROR_MEDIUM_NOT_REWRITABLE;
714 else
715 error_type = BRASERO_BURN_ERROR_NONE;
716
717 if (error_type != BRASERO_BURN_ERROR_NONE) {
718 result = brasero_burn_ask_for_dest_media (burn,
719 error_type,
720 BRASERO_MEDIUM_REWRITABLE|
721 BRASERO_MEDIUM_HAS_DATA,
722 error);
723
724 if (result != BRASERO_BURN_OK)
725 return result;
726
727 goto again;
728 }
729
730 if (!brasero_drive_is_locked (priv->dest, NULL)
731 && !brasero_drive_lock (priv->dest, _("Ongoing blanking process"), &failure)) {
732 g_set_error (error,
733 BRASERO_BURN_ERROR,
734 BRASERO_BURN_ERROR_GENERAL,
735 _("The drive cannot be locked (%s)"),
736 failure);
737 return BRASERO_BURN_ERR;
738 }
739
740 return BRASERO_BURN_OK;
741 }
742
743 static BraseroBurnResult
brasero_burn_lock_dest_media(BraseroBurn * burn,BraseroBurnError * ret_error,GError ** error)744 brasero_burn_lock_dest_media (BraseroBurn *burn,
745 BraseroBurnError *ret_error,
746 GError **error)
747 {
748 gchar *failure;
749 BraseroMedia media;
750 BraseroBurnError berror;
751 BraseroMedium *medium;
752 BraseroBurnResult result;
753 BraseroTrackType *input = NULL;
754 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
755
756 priv->dest = brasero_burn_session_get_burner (priv->session);
757 if (!priv->dest) {
758 g_set_error (error,
759 BRASERO_BURN_ERROR,
760 BRASERO_BURN_ERROR_OUTPUT_NONE,
761 "%s", _("No burner specified"));
762 return BRASERO_BURN_ERR;
763 }
764
765 /* Check the capabilities of the drive */
766 if (!brasero_drive_can_write (priv->dest)) {
767 g_set_error (error,
768 BRASERO_BURN_ERROR,
769 BRASERO_BURN_ERROR_GENERAL,
770 "%s", _("The drive cannot burn"));
771 BRASERO_BURN_NOT_SUPPORTED_LOG (burn);
772 }
773
774 /* NOTE: don't lock the drive here yet as
775 * otherwise we'd be probing forever. */
776 while (brasero_drive_probing (priv->dest)) {
777 result = brasero_burn_sleep (burn, 500);
778 if (result != BRASERO_BURN_OK)
779 return result;
780 }
781
782 medium = brasero_drive_get_medium (priv->dest);
783 if (!medium) {
784 result = BRASERO_BURN_NEED_RELOAD;
785 berror = BRASERO_BURN_ERROR_MEDIUM_NONE;
786 goto end;
787 }
788
789 /* unmount the medium */
790 result = brasero_burn_unmount (burn, medium, error);
791 if (result != BRASERO_BURN_OK)
792 return result;
793
794 result = BRASERO_BURN_OK;
795 berror = BRASERO_BURN_ERROR_NONE;
796
797 media = brasero_medium_get_status (medium);
798 BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_DISC,
799 media,
800 BRASERO_PLUGIN_IO_NONE,
801 "Media inserted is");
802
803 if (media == BRASERO_MEDIUM_NONE) {
804 result = BRASERO_BURN_NEED_RELOAD;
805 berror = BRASERO_BURN_ERROR_MEDIUM_NONE;
806 goto end;
807 }
808
809 if (media == BRASERO_MEDIUM_UNSUPPORTED) {
810 result = BRASERO_BURN_NEED_RELOAD;
811 berror = BRASERO_BURN_ERROR_MEDIUM_INVALID;
812 goto end;
813 }
814
815 if (media == BRASERO_MEDIUM_BUSY) {
816 result = BRASERO_BURN_NEED_RELOAD;
817 berror = BRASERO_BURN_ERROR_DRIVE_BUSY;
818 goto end;
819 }
820
821 /* Make sure that media is supported and
822 * can be written to */
823
824 /* NOTE: Since we did not check the flags
825 * and since they might change, check if the
826 * session is supported without the flags.
827 * We use quite a strict checking though as
828 * from now on we require plugins to be
829 * ready. */
830 result = brasero_burn_session_can_burn (priv->session, FALSE);
831 if (result != BRASERO_BURN_OK) {
832 BRASERO_BURN_LOG ("Inserted media is not supported");
833 result = BRASERO_BURN_NEED_RELOAD;
834 berror = BRASERO_BURN_ERROR_MEDIUM_INVALID;
835 goto end;
836 }
837
838 input = brasero_track_type_new ();
839 brasero_burn_session_get_input_type (priv->session, input);
840
841 if (brasero_track_type_get_has_image (input)) {
842 goffset medium_sec = 0;
843 goffset session_sec = 0;
844
845 /* This test is only valid when it's an image
846 * as input which comes handy when copying
847 * from the same drive as we're sure we do
848 * have an image. */
849 brasero_medium_get_capacity (medium,
850 NULL,
851 &medium_sec);
852 brasero_burn_session_get_size (priv->session,
853 &session_sec,
854 NULL);
855
856 if (session_sec > medium_sec) {
857 BRASERO_BURN_LOG ("Not enough space for image %"G_GOFFSET_FORMAT"/%"G_GOFFSET_FORMAT, session_sec, medium_sec);
858 berror = BRASERO_BURN_ERROR_MEDIUM_SPACE;
859 result = BRASERO_BURN_NEED_RELOAD;
860 goto end;
861 }
862 }
863
864 /* Only lock the drive after all checks succeeded */
865 if (!brasero_drive_is_locked (priv->dest, NULL)
866 && !brasero_drive_lock (priv->dest, _("Ongoing burning process"), &failure)) {
867 brasero_track_type_free (input);
868
869 g_set_error (error,
870 BRASERO_BURN_ERROR,
871 BRASERO_BURN_ERROR_GENERAL,
872 _("The drive cannot be locked (%s)"),
873 failure);
874 return BRASERO_BURN_ERR;
875 }
876
877 end:
878
879 if (result != BRASERO_BURN_OK
880 && brasero_drive_is_locked (priv->dest, NULL))
881 brasero_drive_unlock (priv->dest);
882
883 if (result == BRASERO_BURN_NEED_RELOAD && ret_error)
884 *ret_error = berror;
885
886 brasero_track_type_free (input);
887
888 return result;
889 }
890
891 static BraseroBurnResult
brasero_burn_reload_dest_media(BraseroBurn * burn,BraseroBurnError error_code,GError ** error)892 brasero_burn_reload_dest_media (BraseroBurn *burn,
893 BraseroBurnError error_code,
894 GError **error)
895 {
896 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
897 BraseroMedia required_media;
898 BraseroBurnResult result;
899
900 again:
901
902 /* eject and ask the user to reload a disc */
903 required_media = brasero_burn_session_get_required_media_type (priv->session);
904 required_media &= (BRASERO_MEDIUM_WRITABLE|
905 BRASERO_MEDIUM_CD|
906 BRASERO_MEDIUM_DVD);
907
908 if (required_media == BRASERO_MEDIUM_NONE)
909 required_media = BRASERO_MEDIUM_WRITABLE;
910
911 result = brasero_burn_ask_for_dest_media (burn,
912 error_code,
913 required_media,
914 error);
915 if (result != BRASERO_BURN_OK)
916 return result;
917
918 result = brasero_burn_lock_dest_media (burn,
919 &error_code,
920 error);
921 if (result == BRASERO_BURN_NEED_RELOAD)
922 goto again;
923
924 return result;
925 }
926
927 static BraseroBurnResult
brasero_burn_lock_checksum_media(BraseroBurn * burn,GError ** error)928 brasero_burn_lock_checksum_media (BraseroBurn *burn,
929 GError **error)
930 {
931 gchar *failure;
932 BraseroMedia media;
933 BraseroMedium *medium;
934 BraseroBurnResult result;
935 BraseroBurnError error_type;
936 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
937
938 priv->dest = brasero_burn_session_get_src_drive (priv->session);
939
940 again:
941
942 while (brasero_drive_probing (priv->dest)) {
943 result = brasero_burn_sleep (burn, 500);
944 if (result != BRASERO_BURN_OK)
945 return result;
946 }
947
948 medium = brasero_drive_get_medium (priv->dest);
949 media = brasero_medium_get_status (medium);
950
951 error_type = BRASERO_BURN_ERROR_NONE;
952 BRASERO_BURN_LOG_DISC_TYPE (media, "Waiting for media to checksum");
953
954 if (media == BRASERO_MEDIUM_NONE) {
955 /* NOTE: that's done on purpose since here if the drive is empty
956 * that's because we ejected it */
957 result = brasero_burn_ask_for_dest_media (burn,
958 BRASERO_BURN_WARNING_CHECKSUM,
959 BRASERO_MEDIUM_NONE,
960 error);
961 if (result != BRASERO_BURN_OK)
962 return result;
963 }
964 else if (media == BRASERO_MEDIUM_BUSY)
965 error_type = BRASERO_BURN_ERROR_DRIVE_BUSY;
966 else if (media == BRASERO_MEDIUM_UNSUPPORTED)
967 error_type = BRASERO_BURN_ERROR_MEDIUM_INVALID;
968 else if (media & BRASERO_MEDIUM_BLANK)
969 error_type = BRASERO_BURN_ERROR_MEDIUM_NO_DATA;
970
971 if (error_type != BRASERO_BURN_ERROR_NONE) {
972 result = brasero_burn_ask_for_dest_media (burn,
973 BRASERO_BURN_WARNING_CHECKSUM,
974 BRASERO_MEDIUM_NONE,
975 error);
976 if (result != BRASERO_BURN_OK)
977 return result;
978
979 goto again;
980 }
981
982 if (!brasero_drive_is_locked (priv->dest, NULL)
983 && !brasero_drive_lock (priv->dest, _("Ongoing checksumming operation"), &failure)) {
984 g_set_error (error,
985 BRASERO_BURN_ERROR,
986 BRASERO_BURN_ERROR_GENERAL,
987 _("The drive cannot be locked (%s)"),
988 failure);
989 return BRASERO_BURN_ERR;
990 }
991
992 /* if drive is mounted then unmount before checking anything */
993 /* if (brasero_volume_is_mounted (BRASERO_VOLUME (medium))
994 && !brasero_volume_umount (BRASERO_VOLUME (medium), TRUE, NULL))
995 g_warning ("Couldn't unmount volume in drive: %s",
996 brasero_drive_get_device (priv->dest));
997 */
998
999 return BRASERO_BURN_OK;
1000 }
1001
1002 static BraseroBurnResult
brasero_burn_unlock_src_media(BraseroBurn * burn,GError ** error)1003 brasero_burn_unlock_src_media (BraseroBurn *burn,
1004 GError **error)
1005 {
1006 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1007 BraseroMedium *medium;
1008
1009 if (!priv->src)
1010 return BRASERO_BURN_OK;
1011
1012 /* If we mounted it ourselves, unmount it */
1013 medium = brasero_drive_get_medium (priv->src);
1014 if (priv->mounted_by_us) {
1015 brasero_burn_unmount (burn, medium, error);
1016 priv->mounted_by_us = FALSE;
1017 }
1018
1019 if (brasero_drive_is_locked (priv->src, NULL))
1020 brasero_drive_unlock (priv->src);
1021
1022 /* Never eject the source if we don't need to. Let the user do that. For
1023 * one thing it avoids breaking other applications that are using it
1024 * like for example totem. */
1025 /* if (BRASERO_BURN_SESSION_EJECT (priv->session))
1026 brasero_drive_eject (BRASERO_VOLUME (medium), FALSE, error); */
1027
1028 priv->src = NULL;
1029 return BRASERO_BURN_OK;
1030 }
1031
1032 static BraseroBurnResult
brasero_burn_unlock_dest_media(BraseroBurn * burn,GError ** error)1033 brasero_burn_unlock_dest_media (BraseroBurn *burn,
1034 GError **error)
1035 {
1036 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1037
1038 if (!priv->dest)
1039 return BRASERO_BURN_OK;
1040
1041 if (brasero_drive_is_locked (priv->dest, NULL))
1042 brasero_drive_unlock (priv->dest);
1043
1044 if (!BRASERO_BURN_SESSION_EJECT (priv->session))
1045 brasero_drive_reprobe (priv->dest);
1046 else
1047 brasero_burn_eject (burn, priv->dest, error);
1048
1049 priv->dest = NULL;
1050 return BRASERO_BURN_OK;
1051 }
1052
1053 static BraseroBurnResult
brasero_burn_unlock_medias(BraseroBurn * burn,GError ** error)1054 brasero_burn_unlock_medias (BraseroBurn *burn,
1055 GError **error)
1056 {
1057 brasero_burn_unlock_dest_media (burn, error);
1058 brasero_burn_unlock_src_media (burn, error);
1059
1060 return BRASERO_BURN_OK;
1061 }
1062
1063 static void
brasero_burn_progress_changed(BraseroTaskCtx * task,BraseroBurn * burn)1064 brasero_burn_progress_changed (BraseroTaskCtx *task,
1065 BraseroBurn *burn)
1066 {
1067 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1068 gdouble overall_progress = -1.0;
1069 gdouble task_progress = -1.0;
1070 glong time_remaining = -1;
1071
1072 /* get the task current progress */
1073 if (brasero_task_ctx_get_progress (task, &task_progress) == BRASERO_BURN_OK) {
1074 brasero_task_ctx_get_remaining_time (task, &time_remaining);
1075 overall_progress = (task_progress + (gdouble) priv->tasks_done) /
1076 (gdouble) priv->task_nb;
1077 }
1078 else
1079 overall_progress = (gdouble) priv->tasks_done /
1080 (gdouble) priv->task_nb;
1081
1082 g_signal_emit (burn,
1083 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
1084 0,
1085 overall_progress,
1086 task_progress,
1087 time_remaining);
1088 }
1089
1090 static void
brasero_burn_action_changed(BraseroTask * task,BraseroBurnAction action,BraseroBurn * burn)1091 brasero_burn_action_changed (BraseroTask *task,
1092 BraseroBurnAction action,
1093 BraseroBurn *burn)
1094 {
1095 brasero_burn_action_changed_real (burn, action);
1096 }
1097
1098 /**
1099 * brasero_burn_get_action_string:
1100 * @burn: a #BraseroBurn
1101 * @action: a #BraseroBurnAction
1102 * @string: a #gchar **
1103 *
1104 * This function returns the current action (in @string) of
1105 * an ongoing operation performed by @burn.
1106 * @action is used to set a default string in case there was
1107 * no string set by the backend to describe the current
1108 * operation.
1109 *
1110 **/
1111
1112 void
brasero_burn_get_action_string(BraseroBurn * burn,BraseroBurnAction action,gchar ** string)1113 brasero_burn_get_action_string (BraseroBurn *burn,
1114 BraseroBurnAction action,
1115 gchar **string)
1116 {
1117 BraseroBurnPrivate *priv;
1118
1119 g_return_if_fail (BRASERO_BURN (burn));
1120 g_return_if_fail (string != NULL);
1121
1122 priv = BRASERO_BURN_PRIVATE (burn);
1123 if (action == BRASERO_BURN_ACTION_FINISHED || !priv->task)
1124 (*string) = g_strdup (brasero_burn_action_to_string (action));
1125 else
1126 brasero_task_ctx_get_current_action_string (BRASERO_TASK_CTX (priv->task),
1127 action,
1128 string);
1129 }
1130
1131 /**
1132 * brasero_burn_status:
1133 * @burn: a #BraseroBurn
1134 * @media: a #BraseroMedia or NULL
1135 * @isosize: a #goffset or NULL
1136 * @written: a #goffset or NULL
1137 * @rate: a #guint64 or NULL
1138 *
1139 * Returns various information about the current operation
1140 * in @media (the current media type being burnt),
1141 * @isosize (the size of the data being burnt), @written (the
1142 * number of bytes having been written so far) and @rate
1143 * (the speed at which data are written).
1144 *
1145 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if there is
1146 * an ongoing operation; BRASERO_BURN_NOT_READY otherwise.
1147 **/
1148
1149 BraseroBurnResult
brasero_burn_status(BraseroBurn * burn,BraseroMedia * media,goffset * isosize,goffset * written,guint64 * rate)1150 brasero_burn_status (BraseroBurn *burn,
1151 BraseroMedia *media,
1152 goffset *isosize,
1153 goffset *written,
1154 guint64 *rate)
1155 {
1156 BraseroBurnPrivate *priv;
1157 BraseroBurnResult result;
1158
1159 g_return_val_if_fail (BRASERO_BURN (burn), BRASERO_BURN_ERR);
1160
1161 priv = BRASERO_BURN_PRIVATE (burn);
1162
1163 if (!priv->task)
1164 return BRASERO_BURN_NOT_READY;
1165
1166 if (isosize) {
1167 goffset size_local = 0;
1168
1169 result = brasero_task_ctx_get_session_output_size (BRASERO_TASK_CTX (priv->task),
1170 NULL,
1171 &size_local);
1172 if (result != BRASERO_BURN_OK)
1173 *isosize = -1;
1174 else
1175 *isosize = size_local;
1176 }
1177
1178 if (!brasero_task_is_running (priv->task))
1179 return BRASERO_BURN_NOT_READY;
1180
1181 if (rate)
1182 brasero_task_ctx_get_rate (BRASERO_TASK_CTX (priv->task), rate);
1183
1184 if (written) {
1185 gint64 written_local = 0;
1186
1187 result = brasero_task_ctx_get_written (BRASERO_TASK_CTX (priv->task), &written_local);
1188
1189 if (result != BRASERO_BURN_OK)
1190 *written = -1;
1191 else
1192 *written = written_local;
1193 }
1194
1195 if (!media)
1196 return BRASERO_BURN_OK;
1197
1198 /* return the disc we burn to if:
1199 * - that's the last task to perform
1200 * - brasero_burn_session_is_dest_file returns FALSE
1201 */
1202 if (priv->tasks_done < priv->task_nb - 1) {
1203 BraseroTrackType *input = NULL;
1204
1205 input = brasero_track_type_new ();
1206 brasero_burn_session_get_input_type (priv->session, input);
1207 if (brasero_track_type_get_has_medium (input))
1208 *media = brasero_track_type_get_medium_type (input);
1209 else
1210 *media = BRASERO_MEDIUM_NONE;
1211
1212 brasero_track_type_free (input);
1213 }
1214 else if (brasero_burn_session_is_dest_file (priv->session))
1215 *media = BRASERO_MEDIUM_FILE;
1216 else
1217 *media = brasero_burn_session_get_dest_media (priv->session);
1218
1219 return BRASERO_BURN_OK;
1220 }
1221
1222 static BraseroBurnResult
brasero_burn_ask_for_joliet(BraseroBurn * burn)1223 brasero_burn_ask_for_joliet (BraseroBurn *burn)
1224 {
1225 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1226 BraseroBurnResult result;
1227 GSList *tracks;
1228 GSList *iter;
1229
1230 result = brasero_burn_emit_signal (burn, ASK_DISABLE_JOLIET_SIGNAL, BRASERO_BURN_CANCEL);
1231 if (result != BRASERO_BURN_OK)
1232 return result;
1233
1234 tracks = brasero_burn_session_get_tracks (priv->session);
1235 for (iter = tracks; iter; iter = iter->next) {
1236 BraseroTrack *track;
1237
1238 track = iter->data;
1239 brasero_track_data_rm_fs (BRASERO_TRACK_DATA (track), BRASERO_IMAGE_FS_JOLIET);
1240 }
1241
1242 return BRASERO_BURN_OK;
1243 }
1244
1245 static BraseroBurnResult
brasero_burn_ask_for_location(BraseroBurn * burn,GError * received_error,gboolean is_temporary,GError ** error)1246 brasero_burn_ask_for_location (BraseroBurn *burn,
1247 GError *received_error,
1248 gboolean is_temporary,
1249 GError **error)
1250 {
1251 GValue instance_and_params [3];
1252 GValue return_value;
1253
1254 instance_and_params [0].g_type = 0;
1255 g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (burn));
1256 g_value_set_instance (instance_and_params, burn);
1257
1258 instance_and_params [1].g_type = 0;
1259 g_value_init (instance_and_params + 1, G_TYPE_POINTER);
1260 g_value_set_pointer (instance_and_params + 1, received_error);
1261
1262 instance_and_params [2].g_type = 0;
1263 g_value_init (instance_and_params + 2, G_TYPE_BOOLEAN);
1264 g_value_set_boolean (instance_and_params + 2, is_temporary);
1265
1266 return_value.g_type = 0;
1267 g_value_init (&return_value, G_TYPE_INT);
1268 g_value_set_int (&return_value, BRASERO_BURN_CANCEL);
1269
1270 g_signal_emitv (instance_and_params,
1271 brasero_burn_signals [LOCATION_REQUEST_SIGNAL],
1272 0,
1273 &return_value);
1274
1275 g_value_unset (instance_and_params);
1276 g_value_unset (instance_and_params + 1);
1277
1278 return g_value_get_int (&return_value);
1279 }
1280
1281 static BraseroBurnResult
brasero_burn_run_eraser(BraseroBurn * burn,GError ** error)1282 brasero_burn_run_eraser (BraseroBurn *burn, GError **error)
1283 {
1284 BraseroDrive *drive;
1285 BraseroMedium *medium;
1286 BraseroBurnPrivate *priv;
1287 BraseroBurnResult result;
1288
1289 priv = BRASERO_BURN_PRIVATE (burn);
1290
1291 drive = brasero_burn_session_get_burner (priv->session);
1292 medium = brasero_drive_get_medium (drive);
1293
1294 result = brasero_burn_unmount (burn, medium, error);
1295 if (result != BRASERO_BURN_OK)
1296 return result;
1297
1298 result = brasero_task_run (priv->task, error);
1299 if (result != BRASERO_BURN_OK)
1300 return result;
1301
1302 /* Reprobe. It can happen (like with dvd+rw-format) that
1303 * for the whole OS, the disc doesn't exist during the
1304 * formatting. Wait for the disc to reappear */
1305 /* Likewise, this is necessary when we do a
1306 * simulation before blanking since it blanked the disc
1307 * and then to create all tasks necessary for the real
1308 * burning operation, we'll need the real medium status
1309 * not to include a blanking job again. */
1310 return brasero_burn_reprobe (burn);
1311 }
1312
1313 static BraseroBurnResult
brasero_burn_run_imager(BraseroBurn * burn,gboolean fake,GError ** error)1314 brasero_burn_run_imager (BraseroBurn *burn,
1315 gboolean fake,
1316 GError **error)
1317 {
1318 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1319 BraseroBurnError error_code;
1320 BraseroBurnResult result;
1321 GError *ret_error = NULL;
1322 BraseroMedium *medium;
1323 BraseroDrive *src;
1324
1325 src = brasero_burn_session_get_src_drive (priv->session);
1326
1327 start:
1328
1329 medium = brasero_drive_get_medium (src);
1330 if (medium) {
1331 /* This is just in case */
1332 result = brasero_burn_unmount (burn, medium, error);
1333 if (result != BRASERO_BURN_OK)
1334 return result;
1335 }
1336
1337 /* If it succeeds then the new track(s) will be at the top of
1338 * session tracks stack and therefore usable by the recorder.
1339 * NOTE: it's up to the job to push the current tracks. */
1340 if (fake)
1341 result = brasero_task_check (priv->task, &ret_error);
1342 else
1343 result = brasero_task_run (priv->task, &ret_error);
1344
1345 if (result == BRASERO_BURN_OK) {
1346 if (!fake) {
1347 g_signal_emit (burn,
1348 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
1349 0,
1350 1.0,
1351 1.0,
1352 -1L);
1353 }
1354 return BRASERO_BURN_OK;
1355 }
1356
1357 if (result != BRASERO_BURN_ERR) {
1358 if (error && ret_error)
1359 g_propagate_error (error, ret_error);
1360
1361 return result;
1362 }
1363
1364 if (!ret_error)
1365 return result;
1366
1367 if (brasero_burn_session_is_dest_file (priv->session)) {
1368 gchar *image = NULL;
1369 gchar *toc = NULL;
1370
1371 /* If it was an image that was output, remove it. If that was
1372 * a temporary image, it will be removed by BraseroBurnSession
1373 * object. But if it was a final image, it would be left and
1374 * would clutter the disk, wasting space. */
1375 brasero_burn_session_get_output (priv->session,
1376 &image,
1377 &toc);
1378 if (image)
1379 g_remove (image);
1380 if (toc)
1381 g_remove (toc);
1382 }
1383
1384 /* See if we can recover from the error */
1385 error_code = ret_error->code;
1386 if (error_code == BRASERO_BURN_ERROR_IMAGE_JOLIET) {
1387 /* clean the error anyway since at worst the user will cancel */
1388 g_error_free (ret_error);
1389 ret_error = NULL;
1390
1391 /* some files are not conforming to Joliet standard see
1392 * if the user wants to carry on with a non joliet disc */
1393 result = brasero_burn_ask_for_joliet (burn);
1394 if (result != BRASERO_BURN_OK)
1395 return result;
1396
1397 goto start;
1398 }
1399 else if (error_code == BRASERO_BURN_ERROR_MEDIUM_NO_DATA) {
1400 /* clean the error anyway since at worst the user will cancel */
1401 g_error_free (ret_error);
1402 ret_error = NULL;
1403
1404 /* The media hasn't data on it: ask for a new one. */
1405 result = brasero_burn_reload_src_media (burn,
1406 error_code,
1407 error);
1408 if (result != BRASERO_BURN_OK)
1409 return result;
1410
1411 goto start;
1412 }
1413 else if (error_code == BRASERO_BURN_ERROR_DISK_SPACE
1414 || error_code == BRASERO_BURN_ERROR_PERMISSION
1415 || error_code == BRASERO_BURN_ERROR_TMP_DIRECTORY) {
1416 gboolean is_temp;
1417
1418 /* That's an imager (outputs an image to the disc) so that means
1419 * that here the problem comes from the hard drive being too
1420 * small or we don't have the right permission. */
1421
1422 /* NOTE: Image file creation is always the last to take place
1423 * when it's not temporary. Another job should not take place
1424 * afterwards */
1425 if (!brasero_burn_session_is_dest_file (priv->session))
1426 is_temp = TRUE;
1427 else
1428 is_temp = FALSE;
1429
1430 result = brasero_burn_ask_for_location (burn,
1431 ret_error,
1432 is_temp,
1433 error);
1434
1435 /* clean the error anyway since at worst the user will cancel */
1436 g_error_free (ret_error);
1437 ret_error = NULL;
1438
1439 if (result != BRASERO_BURN_OK)
1440 return result;
1441
1442 goto start;
1443 }
1444
1445 /* If we reached this point that means the error was not recoverable.
1446 * Propagate the error. */
1447 if (error && ret_error)
1448 g_propagate_error (error, ret_error);
1449
1450 return BRASERO_BURN_ERR;
1451 }
1452
1453 static BraseroBurnResult
brasero_burn_can_use_drive_exclusively(BraseroBurn * burn,BraseroDrive * drive)1454 brasero_burn_can_use_drive_exclusively (BraseroBurn *burn,
1455 BraseroDrive *drive)
1456 {
1457 BraseroBurnResult result;
1458
1459 if (!drive)
1460 return BRASERO_BURN_OK;
1461
1462 while (!brasero_drive_can_use_exclusively (drive)) {
1463 BRASERO_BURN_LOG ("Device busy, retrying in 250 ms");
1464 result = brasero_burn_sleep (burn, 250);
1465 if (result != BRASERO_BURN_OK)
1466 return result;
1467 }
1468
1469 return BRASERO_BURN_OK;
1470 }
1471
1472 static BraseroBurnResult
brasero_burn_run_recorder(BraseroBurn * burn,GError ** error)1473 brasero_burn_run_recorder (BraseroBurn *burn, GError **error)
1474 {
1475 gint error_code;
1476 BraseroDrive *src;
1477 BraseroDrive *burner;
1478 GError *ret_error = NULL;
1479 BraseroBurnResult result;
1480 BraseroMedium *src_medium;
1481 BraseroMedium *burnt_medium;
1482 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1483
1484 src = brasero_burn_session_get_src_drive (priv->session);
1485 src_medium = brasero_drive_get_medium (src);
1486
1487 burner = brasero_burn_session_get_burner (priv->session);
1488 burnt_medium = brasero_drive_get_medium (burner);
1489
1490 start:
1491
1492 /* this is just in case */
1493 if (BRASERO_BURN_SESSION_NO_TMP_FILE (priv->session)) {
1494 result = brasero_burn_unmount (burn, src_medium, error);
1495 if (result != BRASERO_BURN_OK)
1496 return result;
1497 }
1498
1499 result = brasero_burn_unmount (burn, burnt_medium, error);
1500 if (result != BRASERO_BURN_OK)
1501 return result;
1502
1503 /* before we start let's see if that drive can be used exclusively.
1504 * Of course, it's not really safe since a process could take a lock
1505 * just after us but at least it'll give some time to HAL and friends
1506 * to finish what they're doing.
1507 * This was done because more than often backends wouldn't be able to
1508 * get a lock on a medium after a simulation. */
1509 result = brasero_burn_can_use_drive_exclusively (burn, burner);
1510 if (result != BRASERO_BURN_OK)
1511 return result;
1512
1513 /* actual running of task */
1514 result = brasero_task_run (priv->task, &ret_error);
1515
1516 /* let's see the results */
1517 if (result == BRASERO_BURN_OK) {
1518 g_signal_emit (burn,
1519 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
1520 0,
1521 1.0,
1522 1.0,
1523 -1L);
1524 return BRASERO_BURN_OK;
1525 }
1526
1527 if (result != BRASERO_BURN_ERR
1528 || !ret_error
1529 || ret_error->domain != BRASERO_BURN_ERROR) {
1530 if (ret_error)
1531 g_propagate_error (error, ret_error);
1532
1533 return result;
1534 }
1535
1536 /* see if error is recoverable */
1537 error_code = ret_error->code;
1538 if (error_code == BRASERO_BURN_ERROR_IMAGE_JOLIET) {
1539 /* NOTE: this error can only come from the source when
1540 * burning on the fly => no need to recreate an imager */
1541
1542 /* some files are not conforming to Joliet standard see
1543 * if the user wants to carry on with a non joliet disc */
1544 result = brasero_burn_ask_for_joliet (burn);
1545 if (result != BRASERO_BURN_OK) {
1546 if (ret_error)
1547 g_propagate_error (error, ret_error);
1548
1549 return result;
1550 }
1551
1552 g_error_free (ret_error);
1553 ret_error = NULL;
1554 goto start;
1555 }
1556 else if (error_code == BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING) {
1557 /* NOTE: this error can only come from the source when
1558 * burning on the fly => no need to recreate an imager */
1559
1560 /* The source media (when copying on the fly) is empty
1561 * so ask the user to reload another media with data */
1562 g_error_free (ret_error);
1563 ret_error = NULL;
1564
1565 result = brasero_burn_reload_src_media (burn,
1566 error_code,
1567 error);
1568 if (result != BRASERO_BURN_OK)
1569 return result;
1570
1571 goto start;
1572 }
1573 else if (error_code == BRASERO_BURN_ERROR_SLOW_DMA) {
1574 guint64 rate;
1575
1576 /* The whole system has just made a great effort. Sometimes it
1577 * helps to let it rest for a sec or two => that's what we do
1578 * before retrying. (That's why usually cdrecord waits a little
1579 * bit but sometimes it doesn't). Another solution would be to
1580 * lower the speed a little (we could do both) */
1581 g_error_free (ret_error);
1582 ret_error = NULL;
1583
1584 result = brasero_burn_sleep (burn, 2000);
1585 if (result != BRASERO_BURN_OK)
1586 return result;
1587
1588 /* set speed at 8x max and even less if speed */
1589 rate = brasero_burn_session_get_rate (priv->session);
1590 if (rate <= BRASERO_SPEED_TO_RATE_CD (8)) {
1591 rate = rate * 3 / 4;
1592 if (rate < CD_RATE)
1593 rate = CD_RATE;
1594 }
1595 else
1596 rate = BRASERO_SPEED_TO_RATE_CD (8);
1597
1598 brasero_burn_session_set_rate (priv->session, rate);
1599 goto start;
1600 }
1601 else if (error_code == BRASERO_BURN_ERROR_MEDIUM_SPACE) {
1602 /* NOTE: this error can only come from the dest drive */
1603
1604 /* clean error and indicates this is a recoverable error */
1605 g_error_free (ret_error);
1606 ret_error = NULL;
1607
1608 /* the space left on the media is insufficient (that's strange
1609 * since we checked):
1610 * the disc is either not rewritable or is too small anyway then
1611 * we ask for a new media.
1612 * It raises the problem of session merging. Indeed at this
1613 * point an image can have been generated that was specifically
1614 * generated for the inserted media. So if we have MERGE/APPEND
1615 * that should fail.
1616 */
1617 if (brasero_burn_session_get_flags (priv->session) &
1618 (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE)) {
1619 g_set_error (error,
1620 BRASERO_BURN_ERROR,
1621 BRASERO_BURN_ERROR_MEDIUM_SPACE,
1622 "%s. %s",
1623 _("Merging data is impossible with this disc"),
1624 _("Not enough space available on the disc"));
1625 return BRASERO_BURN_ERR;
1626 }
1627
1628 /* ask for the destination media reload */
1629 result = brasero_burn_reload_dest_media (burn,
1630 error_code,
1631 error);
1632 if (result != BRASERO_BURN_OK)
1633 return result;
1634
1635 goto start;
1636 }
1637 else if (error_code >= BRASERO_BURN_ERROR_MEDIUM_NONE
1638 && error_code <= BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING) {
1639 /* NOTE: these errors can only come from the dest drive */
1640
1641 /* clean error and indicates this is a recoverable error */
1642 g_error_free (ret_error);
1643 ret_error = NULL;
1644
1645 /* ask for the destination media reload */
1646 result = brasero_burn_reload_dest_media (burn,
1647 error_code,
1648 error);
1649
1650 if (result != BRASERO_BURN_OK)
1651 return result;
1652
1653 goto start;
1654 }
1655
1656 if (ret_error)
1657 g_propagate_error (error, ret_error);
1658
1659 return BRASERO_BURN_ERR;
1660 }
1661
1662 static BraseroBurnResult
brasero_burn_install_missing(BraseroPluginErrorType error,const gchar * details,gpointer user_data)1663 brasero_burn_install_missing (BraseroPluginErrorType error,
1664 const gchar *details,
1665 gpointer user_data)
1666 {
1667 GValue instance_and_params [3];
1668 GValue return_value;
1669
1670 instance_and_params [0].g_type = 0;
1671 g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (user_data));
1672 g_value_set_instance (instance_and_params, user_data);
1673
1674 instance_and_params [1].g_type = 0;
1675 g_value_init (instance_and_params + 1, G_TYPE_INT);
1676 g_value_set_int (instance_and_params + 1, error);
1677
1678 instance_and_params [2].g_type = 0;
1679 g_value_init (instance_and_params + 2, G_TYPE_STRING);
1680 g_value_set_string (instance_and_params + 2, details);
1681
1682 return_value.g_type = 0;
1683 g_value_init (&return_value, G_TYPE_INT);
1684 g_value_set_int (&return_value, BRASERO_BURN_ERROR);
1685
1686 g_signal_emitv (instance_and_params,
1687 brasero_burn_signals [INSTALL_MISSING_SIGNAL],
1688 0,
1689 &return_value);
1690
1691 g_value_unset (instance_and_params);
1692
1693 return g_value_get_int (&return_value);
1694 }
1695
1696 static BraseroBurnResult
brasero_burn_list_missing(BraseroPluginErrorType type,const gchar * detail,gpointer user_data)1697 brasero_burn_list_missing (BraseroPluginErrorType type,
1698 const gchar *detail,
1699 gpointer user_data)
1700 {
1701 GString *string = user_data;
1702
1703 if (type == BRASERO_PLUGIN_ERROR_MISSING_APP ||
1704 type == BRASERO_PLUGIN_ERROR_SYMBOLIC_LINK_APP ||
1705 type == BRASERO_PLUGIN_ERROR_WRONG_APP_VERSION) {
1706 g_string_append_c (string, '\n');
1707 /* Translators: %s is the name of a missing application */
1708 g_string_append_printf (string, _("%s (application)"), detail);
1709 }
1710 else if (type == BRASERO_PLUGIN_ERROR_MISSING_LIBRARY ||
1711 type == BRASERO_PLUGIN_ERROR_LIBRARY_VERSION) {
1712 g_string_append_c (string, '\n');
1713 /* Translators: %s is the name of a missing library */
1714 g_string_append_printf (string, _("%s (library)"), detail);
1715 }
1716 else if (type == BRASERO_PLUGIN_ERROR_MISSING_GSTREAMER_PLUGIN) {
1717 g_string_append_c (string, '\n');
1718 /* Translators: %s is the name of a missing GStreamer plugin */
1719 g_string_append_printf (string, _("%s (GStreamer plugin)"), detail);
1720 }
1721
1722 return BRASERO_BURN_OK;
1723 }
1724
1725 static BraseroBurnResult
brasero_burn_check_session_consistency(BraseroBurn * burn,BraseroTrackType * output,GError ** error)1726 brasero_burn_check_session_consistency (BraseroBurn *burn,
1727 BraseroTrackType *output,
1728 GError **error)
1729 {
1730 BraseroBurnFlag flag;
1731 BraseroBurnFlag flags;
1732 BraseroBurnFlag retval;
1733 BraseroBurnResult result;
1734 BraseroTrackType *input = NULL;
1735 BraseroBurnFlag supported = BRASERO_BURN_FLAG_NONE;
1736 BraseroBurnFlag compulsory = BRASERO_BURN_FLAG_NONE;
1737 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1738
1739 BRASERO_BURN_DEBUG (burn, "Checking session consistency");
1740
1741 /* make sure there is a track in the session. */
1742 input = brasero_track_type_new ();
1743 brasero_burn_session_get_input_type (priv->session, input);
1744
1745 if (brasero_track_type_is_empty (input)) {
1746 brasero_track_type_free (input);
1747
1748 BRASERO_BURN_DEBUG (burn, "No track set");
1749 g_set_error (error,
1750 BRASERO_BURN_ERROR,
1751 BRASERO_BURN_ERROR_GENERAL,
1752 "%s", _("There is no track to burn"));
1753 return BRASERO_BURN_ERR;
1754 }
1755
1756 /* No need to check if a burner was set as this
1757 * is done when locking. */
1758
1759 /* save then wipe out flags from session to check them one by one */
1760 flags = brasero_burn_session_get_flags (priv->session);
1761 brasero_burn_session_set_flags (BRASERO_BURN_SESSION (priv->session), BRASERO_BURN_FLAG_NONE);
1762
1763 if (!output || brasero_track_type_get_has_medium (output))
1764 result = brasero_burn_session_get_burn_flags (priv->session,
1765 &supported,
1766 &compulsory);
1767 else
1768 result = brasero_caps_session_get_image_flags (input,
1769 output,
1770 &supported,
1771 &compulsory);
1772
1773 if (result != BRASERO_BURN_OK) {
1774 brasero_track_type_free (input);
1775 return result;
1776 }
1777
1778 for (flag = 1; flag < BRASERO_BURN_FLAG_LAST; flag <<= 1) {
1779 /* see if this flag was originally set */
1780 if (!(flags & flag))
1781 continue;
1782
1783 /* Check each flag before re-adding it. Emit warnings to user
1784 * to know if he wants to carry on for some flags when they are
1785 * not supported; namely DUMMY. Other flags trigger an error.
1786 * No need for BURNPROOF since that usually means it is just the
1787 * media type that doesn't need it. */
1788 if (supported & flag) {
1789 brasero_burn_session_add_flag (priv->session, flag);
1790
1791 if (!output || brasero_track_type_get_has_medium (output))
1792 result = brasero_burn_session_get_burn_flags (priv->session,
1793 &supported,
1794 &compulsory);
1795 else
1796 result = brasero_caps_session_get_image_flags (input,
1797 output,
1798 &supported,
1799 &compulsory);
1800 }
1801 else {
1802 BRASERO_BURN_LOG_FLAGS (flag, "Flag set but not supported:");
1803
1804 if (flag & BRASERO_BURN_FLAG_DUMMY) {
1805 /* This is simply a warning that it's not possible */
1806
1807 }
1808 else if (flag & BRASERO_BURN_FLAG_MERGE) {
1809 brasero_track_type_free (input);
1810
1811 /* we pay attention to one flag in particular
1812 * (MERGE) if it was set then it must be
1813 * supported. Otherwise error out. */
1814 g_set_error (error,
1815 BRASERO_BURN_ERROR,
1816 BRASERO_BURN_ERROR_GENERAL,
1817 "%s", _("Merging data is impossible with this disc"));
1818 return BRASERO_BURN_ERR;
1819 }
1820 /* No need to tell the user burnproof is not supported
1821 * as these drives handle errors differently which makes
1822 * burnproof useless for them. */
1823 }
1824 }
1825 brasero_track_type_free (input);
1826
1827 retval = brasero_burn_session_get_flags (priv->session);
1828 if (retval != flags)
1829 BRASERO_BURN_LOG_FLAGS (retval, "Some flags were not supported. Corrected to");
1830
1831 if (retval != (retval | compulsory)) {
1832 retval |= compulsory;
1833 BRASERO_BURN_LOG_FLAGS (retval, "Some compulsory flags were forgotten. Corrected to");
1834 }
1835
1836 brasero_burn_session_set_flags (priv->session, retval);
1837 BRASERO_BURN_LOG_FLAGS (retval, "Flags after checking =");
1838
1839 /* Check missing applications/GStreamer plugins.
1840 * This is the best place. */
1841 brasero_burn_session_set_strict_support (BRASERO_BURN_SESSION (priv->session), TRUE);
1842 result = brasero_burn_session_can_burn (priv->session, FALSE);
1843 brasero_burn_session_set_strict_support (BRASERO_BURN_SESSION (priv->session), FALSE);
1844
1845 if (result == BRASERO_BURN_OK)
1846 return result;
1847
1848 result = brasero_burn_session_can_burn (priv->session, FALSE);
1849 if (result != BRASERO_BURN_OK)
1850 return result;
1851
1852 result = brasero_session_foreach_plugin_error (priv->session,
1853 brasero_burn_install_missing,
1854 burn);
1855 if (result != BRASERO_BURN_OK) {
1856 if (result != BRASERO_BURN_CANCEL) {
1857 GString *string;
1858
1859 string = g_string_new (_("Please install the following required applications and libraries manually and try again:"));
1860 brasero_session_foreach_plugin_error (priv->session,
1861 brasero_burn_list_missing,
1862 string);
1863 g_set_error (error,
1864 BRASERO_BURN_ERROR,
1865 BRASERO_BURN_ERROR_MISSING_APP_AND_PLUGIN,
1866 "%s", string->str);
1867
1868 g_string_free (string, TRUE);
1869 }
1870
1871 return BRASERO_BURN_ERR;
1872 }
1873
1874 return BRASERO_BURN_OK;
1875 }
1876
1877 static BraseroBurnResult
brasero_burn_check_data_loss(BraseroBurn * burn,BraseroTrackType * temp_output,GError ** error)1878 brasero_burn_check_data_loss (BraseroBurn *burn,
1879 BraseroTrackType *temp_output,
1880 GError **error)
1881 {
1882 BraseroMedia media;
1883 BraseroBurnFlag flags;
1884 BraseroTrackType *input;
1885 BraseroBurnResult result;
1886 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
1887
1888 if (!temp_output) {
1889 BraseroTrackType *output;
1890
1891 output = brasero_track_type_new ();
1892 brasero_burn_session_get_output_type (priv->session, output);
1893 if (!brasero_track_type_get_has_medium (output)) {
1894 brasero_track_type_free (output);
1895 return BRASERO_BURN_OK;
1896 }
1897
1898 media = brasero_track_type_get_medium_type (output);
1899 brasero_track_type_free (output);
1900 }
1901 else {
1902 if (!brasero_track_type_get_has_medium (temp_output))
1903 return BRASERO_BURN_OK;
1904
1905 media = brasero_track_type_get_medium_type (temp_output);
1906 }
1907
1908 input = brasero_track_type_new ();
1909 brasero_burn_session_get_input_type (priv->session, input);
1910 flags = brasero_burn_session_get_flags (priv->session);
1911
1912 if (media & (BRASERO_MEDIUM_HAS_DATA|BRASERO_MEDIUM_HAS_AUDIO)) {
1913 if (flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) {
1914 /* There is an error if APPEND was set since this disc is not
1915 * supported without a prior blanking. */
1916
1917 /* we warn the user is going to lose data even if in the case of
1918 * DVD+/-RW we don't really blank the disc we rather overwrite */
1919 result = brasero_burn_emit_signal (burn,
1920 WARN_DATA_LOSS_SIGNAL,
1921 BRASERO_BURN_CANCEL);
1922 if (result == BRASERO_BURN_NEED_RELOAD)
1923 goto reload;
1924
1925 if (result != BRASERO_BURN_OK) {
1926 brasero_track_type_free (input);
1927 return result;
1928 }
1929 }
1930 else {
1931 /* A few special warnings for the discs with data/audio on them
1932 * that don't need prior blanking or can't be blanked */
1933 if ((media & BRASERO_MEDIUM_CD)
1934 && brasero_track_type_get_has_stream (input)
1935 && !BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (input))) {
1936 /* We'd rather blank and rewrite a disc rather than
1937 * append audio to appendable disc. That's because audio
1938 * tracks have little chance to be readable by common CD
1939 * player as last tracks */
1940 result = brasero_burn_emit_signal (burn,
1941 WARN_AUDIO_TO_APPENDABLE_SIGNAL,
1942 BRASERO_BURN_CANCEL);
1943 if (result == BRASERO_BURN_NEED_RELOAD)
1944 goto reload;
1945
1946 if (result != BRASERO_BURN_OK) {
1947 brasero_track_type_free (input);
1948 return result;
1949 }
1950 }
1951
1952 /* NOTE: if input is AUDIO we don't care since the OS
1953 * will load the last session of DATA anyway */
1954 if ((media & BRASERO_MEDIUM_HAS_DATA)
1955 && brasero_track_type_get_has_data (input)
1956 && !(flags & BRASERO_BURN_FLAG_MERGE)) {
1957 /* warn the users that their previous data
1958 * session (s) will not be mounted by default by
1959 * the OS and that it'll be invisible */
1960 result = brasero_burn_emit_signal (burn,
1961 WARN_PREVIOUS_SESSION_LOSS_SIGNAL,
1962 BRASERO_BURN_CANCEL);
1963
1964 if (result == BRASERO_BURN_RETRY) {
1965 /* Wipe out the current flags,
1966 * Add a new one
1967 * Recheck the result */
1968 brasero_burn_session_pop_settings (priv->session);
1969 brasero_burn_session_push_settings (priv->session);
1970 brasero_burn_session_add_flag (priv->session, BRASERO_BURN_FLAG_MERGE);
1971 result = brasero_burn_check_session_consistency (burn, NULL, error);
1972 if (result != BRASERO_BURN_OK)
1973 return result;
1974 }
1975
1976 if (result == BRASERO_BURN_NEED_RELOAD)
1977 goto reload;
1978
1979 if (result != BRASERO_BURN_OK) {
1980 brasero_track_type_free (input);
1981 return result;
1982 }
1983 }
1984 }
1985 }
1986
1987 if (media & BRASERO_MEDIUM_REWRITABLE) {
1988 /* emits a warning for the user if it's a rewritable
1989 * disc and he wants to write only audio tracks on it */
1990
1991 /* NOTE: no need to error out here since the only thing
1992 * we are interested in is if it is AUDIO or not or if
1993 * the disc we are copying has audio tracks only or not */
1994 if (brasero_track_type_get_has_stream (input)
1995 && !BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (input))) {
1996 result = brasero_burn_emit_signal (burn,
1997 WARN_REWRITABLE_SIGNAL,
1998 BRASERO_BURN_CANCEL);
1999
2000 if (result == BRASERO_BURN_NEED_RELOAD)
2001 goto reload;
2002
2003 if (result != BRASERO_BURN_OK) {
2004 brasero_track_type_free (input);
2005 return result;
2006 }
2007 }
2008
2009 if (brasero_track_type_get_has_medium (input)
2010 && (brasero_track_type_get_medium_type (input) & BRASERO_MEDIUM_HAS_AUDIO)) {
2011 result = brasero_burn_emit_signal (burn,
2012 WARN_REWRITABLE_SIGNAL,
2013 BRASERO_BURN_CANCEL);
2014
2015 if (result == BRASERO_BURN_NEED_RELOAD)
2016 goto reload;
2017
2018 if (result != BRASERO_BURN_OK) {
2019 brasero_track_type_free (input);
2020 return result;
2021 }
2022 }
2023 }
2024
2025 brasero_track_type_free (input);
2026
2027 return BRASERO_BURN_OK;
2028
2029 reload:
2030
2031 brasero_track_type_free (input);
2032
2033 result = brasero_burn_reload_dest_media (burn, BRASERO_BURN_ERROR_NONE, error);
2034 if (result != BRASERO_BURN_OK)
2035 return result;
2036
2037 return BRASERO_BURN_RETRY;
2038 }
2039
2040 /* FIXME: at the moment we don't allow for mixed CD type */
2041 static BraseroBurnResult
brasero_burn_run_tasks(BraseroBurn * burn,gboolean erase_allowed,BraseroTrackType * temp_output,gboolean * dummy_session,GError ** error)2042 brasero_burn_run_tasks (BraseroBurn *burn,
2043 gboolean erase_allowed,
2044 BraseroTrackType *temp_output,
2045 gboolean *dummy_session,
2046 GError **error)
2047 {
2048 BraseroBurnResult result;
2049 GSList *tasks, *next, *iter;
2050 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (burn);
2051
2052 /* push the session settings to keep the original session untainted */
2053 brasero_burn_session_push_settings (priv->session);
2054
2055 /* check flags consistency */
2056 result = brasero_burn_check_session_consistency (burn, temp_output, error);
2057 if (result != BRASERO_BURN_OK) {
2058 brasero_burn_session_pop_settings (priv->session);
2059 return result;
2060 }
2061
2062 /* performed some additional tests that can only be performed at this
2063 * point. They are mere warnings. */
2064 result = brasero_burn_check_data_loss (burn, temp_output, error);
2065 if (result != BRASERO_BURN_OK) {
2066 brasero_burn_session_pop_settings (priv->session);
2067 return result;
2068 }
2069
2070 tasks = brasero_burn_caps_new_task (priv->caps,
2071 priv->session,
2072 temp_output,
2073 error);
2074 if (!tasks) {
2075 brasero_burn_session_pop_settings (priv->session);
2076 return BRASERO_BURN_NOT_SUPPORTED;
2077 }
2078
2079 priv->tasks_done = 0;
2080 priv->task_nb = g_slist_length (tasks);
2081 BRASERO_BURN_LOG ("%i tasks to perform", priv->task_nb);
2082
2083 /* run all imaging tasks first */
2084 for (iter = tasks; iter; iter = next) {
2085 goffset len = 0;
2086 BraseroDrive *drive;
2087 BraseroMedium *medium;
2088 BraseroTaskAction action;
2089
2090 next = iter->next;
2091 priv->task = iter->data;
2092 tasks = g_slist_remove (tasks, priv->task);
2093
2094 g_signal_connect (priv->task,
2095 "progress-changed",
2096 G_CALLBACK (brasero_burn_progress_changed),
2097 burn);
2098 g_signal_connect (priv->task,
2099 "action-changed",
2100 G_CALLBACK (brasero_burn_action_changed),
2101 burn);
2102
2103 /* see what type of task it is. It could be a blank/erase one. */
2104 /* FIXME!
2105 * If so then that's time to test the size of the image against
2106 * the size of the disc since erasing/formatting is always left
2107 * for the end, just before burning. We would not like to
2108 * blank a disc and tell the user right after that the size of
2109 * the disc is not enough. */
2110 action = brasero_task_ctx_get_action (BRASERO_TASK_CTX (priv->task));
2111 if (action == BRASERO_TASK_ACTION_ERASE) {
2112 BraseroTrackType *type;
2113
2114 /* FIXME: how could it be possible for a drive to test
2115 * with a CLOSED CDRW for example. Maybe we should
2116 * format/blank anyway. */
2117
2118 /* This is to avoid blanking a medium without knowing
2119 * if the data will fit on it. At this point we do know
2120 * what the size of the data is going to be. */
2121 type = brasero_track_type_new ();
2122 brasero_burn_session_get_input_type (priv->session, type);
2123 if (brasero_track_type_get_has_image (type)
2124 || brasero_track_type_get_has_medium (type)) {
2125 BraseroMedium *medium;
2126 goffset session_sec = 0;
2127 goffset medium_sec = 0;
2128
2129 medium = brasero_drive_get_medium (priv->dest);
2130 brasero_medium_get_capacity (medium,
2131 NULL,
2132 &medium_sec);
2133
2134 brasero_burn_session_get_size (priv->session,
2135 &session_sec,
2136 NULL);
2137
2138 if (session_sec > medium_sec) {
2139 BRASERO_BURN_LOG ("Not enough space on medium %"G_GOFFSET_FORMAT"/%"G_GOFFSET_FORMAT, session_sec, medium_sec);
2140 result = brasero_burn_reload_dest_media (burn,
2141 BRASERO_BURN_ERROR_MEDIUM_SPACE,
2142 error);
2143 if (result == BRASERO_BURN_OK)
2144 result = BRASERO_BURN_RETRY;
2145
2146 break;
2147 }
2148 }
2149 brasero_track_type_free (type);
2150
2151 /* This is to avoid a potential problem when running a
2152 * dummy session first. When running dummy session the
2153 * media gets erased if need be. Since it is not
2154 * reloaded afterwards, for brasero it has still got
2155 * data on it when we get to the real recording. */
2156 if (erase_allowed) {
2157 result = brasero_burn_run_eraser (burn, error);
2158 if (result == BRASERO_BURN_CANCEL)
2159 return result;
2160
2161 /* If the erasing process did not work then do
2162 * not fail and cancel the entire session but
2163 * ask the user if he wants to insert another
2164 * disc instead. */
2165 if (result != BRASERO_BURN_OK) {
2166 BraseroBurnResult local_result;
2167
2168 local_result = brasero_burn_emit_signal (burn,
2169 BLANK_FAILURE_SIGNAL,
2170 BRASERO_BURN_ERR);
2171 if (local_result == BRASERO_BURN_OK) {
2172 local_result = brasero_burn_reload_dest_media (burn,
2173 BRASERO_BURN_ERROR_NONE,
2174 NULL);
2175 if (local_result == BRASERO_BURN_OK)
2176 result = BRASERO_BURN_RETRY;
2177 }
2178
2179 break;
2180 }
2181
2182 /* Since we blanked/formatted we need to recheck the burn
2183 * flags with the new medium type as some flags could have
2184 * been given the benefit of the double (MULTI with a CLOSED
2185 * CD for example). Recheck the original flags as they were
2186 * passed. */
2187 /* FIXME: for some important flags we should warn the user
2188 * that it won't be possible */
2189 brasero_burn_session_pop_settings (priv->session);
2190 brasero_burn_session_push_settings (priv->session);
2191 result = brasero_burn_check_session_consistency (burn, temp_output,error);
2192 if (result != BRASERO_BURN_OK)
2193 break;
2194 }
2195 else
2196 result = BRASERO_BURN_OK;
2197
2198 g_object_unref (priv->task);
2199 priv->task = NULL;
2200 priv->tasks_done ++;
2201
2202 continue;
2203 }
2204
2205 /* Init the task and set the task output size. The task should
2206 * then check that the disc has enough space. If the output is
2207 * to the hard drive it will be done afterwards when not in fake
2208 * mode. */
2209 result = brasero_burn_run_imager (burn, TRUE, error);
2210 if (result != BRASERO_BURN_OK)
2211 break;
2212
2213 /* try to get the output size */
2214 brasero_task_ctx_get_session_output_size (BRASERO_TASK_CTX (priv->task),
2215 &len,
2216 NULL);
2217
2218 drive = brasero_burn_session_get_burner (priv->session);
2219 medium = brasero_drive_get_medium (drive);
2220
2221 if (brasero_burn_session_get_flags (priv->session) & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
2222 priv->session_start = brasero_medium_get_next_writable_address (medium);
2223 else
2224 priv->session_start = 0;
2225
2226 priv->session_end = priv->session_start + len;
2227
2228 BRASERO_BURN_LOG ("Burning from %lld to %lld",
2229 priv->session_start,
2230 priv->session_end);
2231
2232 /* see if we reached a recording task: it's the last task */
2233 if (!next) {
2234 if (!brasero_burn_session_is_dest_file (priv->session)) {
2235 *dummy_session = (brasero_burn_session_get_flags (priv->session) & BRASERO_BURN_FLAG_DUMMY);
2236 result = brasero_burn_run_recorder (burn, error);
2237 }
2238 else
2239 result = brasero_burn_run_imager (burn, FALSE, error);
2240
2241 if (result == BRASERO_BURN_OK)
2242 priv->tasks_done ++;
2243
2244 break;
2245 }
2246
2247 /* run the imager */
2248 result = brasero_burn_run_imager (burn, FALSE, error);
2249 if (result != BRASERO_BURN_OK)
2250 break;
2251
2252 g_object_unref (priv->task);
2253 priv->task = NULL;
2254 priv->tasks_done ++;
2255 }
2256
2257 /* restore the session settings. Keep the used flags
2258 * nevertheless to make sure we actually use the flags that were
2259 * set after checking for session consistency. */
2260 brasero_burn_session_pop_settings (priv->session);
2261
2262 if (priv->task) {
2263 g_object_unref (priv->task);
2264 priv->task = NULL;
2265 }
2266
2267 g_slist_foreach (tasks, (GFunc) g_object_unref, NULL);
2268 g_slist_free (tasks);
2269
2270 return result;
2271 }
2272
2273 static BraseroBurnResult
brasero_burn_check_real(BraseroBurn * self,BraseroTrack * track,GError ** error)2274 brasero_burn_check_real (BraseroBurn *self,
2275 BraseroTrack *track,
2276 GError **error)
2277 {
2278 BraseroBurnResult result;
2279 BraseroBurnPrivate *priv;
2280
2281 priv = BRASERO_BURN_PRIVATE (self);
2282
2283 BRASERO_BURN_LOG ("Starting to check track integrity");
2284
2285 /* get the task and run it skip it otherwise */
2286 priv->task = brasero_burn_caps_new_checksuming_task (priv->caps,
2287 priv->session,
2288 NULL);
2289 if (priv->task) {
2290 priv->task_nb = 1;
2291 priv->tasks_done = 0;
2292 g_signal_connect (priv->task,
2293 "progress-changed",
2294 G_CALLBACK (brasero_burn_progress_changed),
2295 self);
2296 g_signal_connect (priv->task,
2297 "action-changed",
2298 G_CALLBACK (brasero_burn_action_changed),
2299 self);
2300
2301
2302 /* make sure one last time it is not mounted IF and only IF the
2303 * checksum type is NOT FILE_MD5 */
2304 /* it seems to work without unmounting ... */
2305 /* if (medium
2306 * && brasero_volume_is_mounted (BRASERO_VOLUME (medium))
2307 * && !brasero_volume_umount (BRASERO_VOLUME (medium), TRUE, NULL)) {
2308 * g_set_error (error,
2309 * BRASERO_BURN_ERROR,
2310 * BRASERO_BURN_ERROR_DRIVE_BUSY,
2311 * "%s. %s",
2312 * _("The drive is busy"),
2313 * _("Make sure another application is not using it"));
2314 * return BRASERO_BURN_ERR;
2315 * }
2316 */
2317
2318 result = brasero_task_run (priv->task, error);
2319 g_signal_emit (self,
2320 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL],
2321 0,
2322 1.0,
2323 1.0,
2324 -1L);
2325
2326 g_object_unref (priv->task);
2327 priv->task = NULL;
2328 }
2329 else {
2330 BRASERO_BURN_LOG ("The track cannot be checked");
2331 return BRASERO_BURN_OK;
2332 }
2333
2334 return result;
2335 }
2336
2337 static void
brasero_burn_unset_checksums(BraseroBurn * self)2338 brasero_burn_unset_checksums (BraseroBurn *self)
2339 {
2340 GSList *tracks;
2341 BraseroTrackType *type;
2342 BraseroBurnPrivate *priv;
2343
2344 priv = BRASERO_BURN_PRIVATE (self);
2345
2346 tracks = brasero_burn_session_get_tracks (priv->session);
2347 type = brasero_track_type_new ();
2348 for (; tracks; tracks = tracks->next) {
2349 BraseroTrack *track;
2350
2351 track = tracks->data;
2352 brasero_track_get_track_type (track, type);
2353 if (!brasero_track_type_get_has_image (type)
2354 && !brasero_track_type_get_has_medium (type))
2355 brasero_track_set_checksum (track,
2356 BRASERO_CHECKSUM_NONE,
2357 NULL);
2358 }
2359
2360 brasero_track_type_free (type);
2361 }
2362
2363 static BraseroBurnResult
brasero_burn_record_session(BraseroBurn * burn,gboolean erase_allowed,BraseroTrackType * temp_output,GError ** error)2364 brasero_burn_record_session (BraseroBurn *burn,
2365 gboolean erase_allowed,
2366 BraseroTrackType *temp_output,
2367 GError **error)
2368 {
2369 gboolean dummy_session = FALSE;
2370 const gchar *checksum = NULL;
2371 BraseroTrack *track = NULL;
2372 BraseroChecksumType type;
2373 BraseroBurnPrivate *priv;
2374 BraseroBurnResult result;
2375 GError *ret_error = NULL;
2376 GSList *tracks;
2377
2378 priv = BRASERO_BURN_PRIVATE (burn);
2379
2380 /* unset checksum since no image has the exact
2381 * same even if it is created from the same files */
2382 brasero_burn_unset_checksums (burn);
2383
2384 do {
2385 if (ret_error) {
2386 g_error_free (ret_error);
2387 ret_error = NULL;
2388 }
2389
2390 result = brasero_burn_run_tasks (burn,
2391 erase_allowed,
2392 temp_output,
2393 &dummy_session,
2394 &ret_error);
2395 } while (result == BRASERO_BURN_RETRY);
2396
2397 if (result != BRASERO_BURN_OK) {
2398 /* handle errors */
2399 if (ret_error) {
2400 g_propagate_error (error, ret_error);
2401 ret_error = NULL;
2402 }
2403
2404 return result;
2405 }
2406
2407 if (brasero_burn_session_is_dest_file (priv->session))
2408 return BRASERO_BURN_OK;
2409
2410 if (dummy_session) {
2411 /* if we are in dummy mode and successfully completed then:
2412 * - no need to checksum the media afterward (done later)
2413 * - no eject to have automatic real burning */
2414
2415 BRASERO_BURN_DEBUG (burn, "Dummy session successfully finished");
2416
2417 /* recording was successful, so tell it */
2418 brasero_burn_action_changed_real (burn, BRASERO_BURN_ACTION_FINISHED);
2419
2420 /* need to try again but this time for real */
2421 result = brasero_burn_emit_signal (burn,
2422 DUMMY_SUCCESS_SIGNAL,
2423 BRASERO_BURN_OK);
2424 if (result != BRASERO_BURN_OK)
2425 return result;
2426
2427 /* unset checksum since no image has the exact same even if it
2428 * is created from the same files */
2429 brasero_burn_unset_checksums (burn);
2430
2431 /* remove dummy flag and restart real burning calling ourselves
2432 * NOTE: don't bother to push the session. We know the changes
2433 * that were made. */
2434 brasero_burn_session_remove_flag (priv->session, BRASERO_BURN_FLAG_DUMMY);
2435 result = brasero_burn_record_session (burn, FALSE, temp_output, error);
2436 brasero_burn_session_add_flag (priv->session, BRASERO_BURN_FLAG_DUMMY);
2437
2438 return result;
2439 }
2440
2441 /* see if we have a checksum generated for the session if so use
2442 * it to check if the recording went well remaining on the top of
2443 * the session should be the last track burnt/imaged */
2444 tracks = brasero_burn_session_get_tracks (priv->session);
2445 if (g_slist_length (tracks) != 1)
2446 return BRASERO_BURN_OK;
2447
2448 track = tracks->data;
2449 type = brasero_track_get_checksum_type (track);
2450 if (type == BRASERO_CHECKSUM_MD5
2451 || type == BRASERO_CHECKSUM_SHA1
2452 || type == BRASERO_CHECKSUM_SHA256)
2453 checksum = brasero_track_get_checksum (track);
2454 else if (type == BRASERO_CHECKSUM_MD5_FILE)
2455 checksum = BRASERO_MD5_FILE;
2456 else if (type == BRASERO_CHECKSUM_SHA1_FILE)
2457 checksum = BRASERO_SHA1_FILE;
2458 else if (type == BRASERO_CHECKSUM_SHA256_FILE)
2459 checksum = BRASERO_SHA256_FILE;
2460 else
2461 return BRASERO_BURN_OK;
2462
2463 /* recording was successful, so tell it */
2464 brasero_burn_action_changed_real (burn, BRASERO_BURN_ACTION_FINISHED);
2465
2466 /* the idea is to push a new track on the stack with
2467 * the current disc burnt and the checksum generated
2468 * during the session recording */
2469 brasero_burn_session_push_tracks (priv->session);
2470
2471 track = BRASERO_TRACK (brasero_track_disc_new ());
2472 brasero_track_set_checksum (BRASERO_TRACK (track),
2473 type,
2474 checksum);
2475
2476 brasero_track_disc_set_drive (BRASERO_TRACK_DISC (track), brasero_burn_session_get_burner (priv->session));
2477 brasero_burn_session_add_track (priv->session, track, NULL);
2478
2479 /* It's good practice to unref the track afterwards as we don't need it
2480 * anymore. BraseroBurnSession refs it. */
2481 g_object_unref (track);
2482
2483 BRASERO_BURN_DEBUG (burn, "Preparing to checksum (type %i %s)", type, checksum);
2484
2485 /* reprobe the medium and wait for it to be probed */
2486 result = brasero_burn_reprobe (burn);
2487 if (result != BRASERO_BURN_OK) {
2488 brasero_burn_session_pop_tracks (priv->session);
2489 return result;
2490 }
2491
2492 /* Why do we do this?
2493 * Because for a lot of medium types the size
2494 * of the track return is not the real size of the
2495 * data that was written; examples
2496 * - CD that was written in SAO mode
2497 * - a DVD-R which usually aligns its track size
2498 * to a 16 block boundary
2499 */
2500 if (type == BRASERO_CHECKSUM_MD5
2501 || type == BRASERO_CHECKSUM_SHA1
2502 || type == BRASERO_CHECKSUM_SHA256) {
2503 GValue *value;
2504
2505 /* get the last written track address */
2506 value = g_new0 (GValue, 1);
2507 g_value_init (value, G_TYPE_UINT64);
2508
2509 BRASERO_BURN_LOG ("Start of last written track address == %lli", priv->session_start);
2510 g_value_set_uint64 (value, priv->session_start);
2511 brasero_track_tag_add (track,
2512 BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
2513 value);
2514
2515 value = g_new0 (GValue, 1);
2516 g_value_init (value, G_TYPE_UINT64);
2517
2518 BRASERO_BURN_LOG ("End of last written track address == %lli", priv->session_end);
2519 g_value_set_uint64 (value, priv->session_end);
2520 brasero_track_tag_add (track,
2521 BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
2522 value);
2523 }
2524
2525 result = brasero_burn_check_real (burn, track, error);
2526 brasero_burn_session_pop_tracks (priv->session);
2527
2528 if (result == BRASERO_BURN_CANCEL) {
2529 /* change the result value so we won't stop here if there are
2530 * other copies to be made */
2531 result = BRASERO_BURN_OK;
2532 }
2533
2534 return result;
2535 }
2536
2537 /**
2538 * brasero_burn_check:
2539 * @burn: a #BraseroBurn
2540 * @session: a #BraseroBurnSession
2541 * @error: a #GError
2542 *
2543 * Checks the integrity of a medium according to the parameters
2544 * set in @session. The medium must be inserted in the #BraseroDrive
2545 * set as the source of a #BraseroTrackDisc track inserted in @session.
2546 *
2547 * Return value: a #BraseroBurnResult. The result of the operation.
2548 * BRASERO_BURN_OK if it was successful.
2549 **/
2550
2551 BraseroBurnResult
brasero_burn_check(BraseroBurn * self,BraseroBurnSession * session,GError ** error)2552 brasero_burn_check (BraseroBurn *self,
2553 BraseroBurnSession *session,
2554 GError **error)
2555 {
2556 GSList *tracks;
2557 BraseroTrack *track;
2558 BraseroBurnResult result;
2559 BraseroBurnPrivate *priv;
2560
2561 g_return_val_if_fail (BRASERO_IS_BURN (self), BRASERO_BURN_ERR);
2562 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
2563
2564 priv = BRASERO_BURN_PRIVATE (self);
2565
2566 g_object_ref (session);
2567 priv->session = session;
2568
2569 /* NOTE: no need to check for parameters here;
2570 * that'll be done when asking for a task */
2571 tracks = brasero_burn_session_get_tracks (priv->session);
2572 if (g_slist_length (tracks) != 1) {
2573 g_set_error (error,
2574 BRASERO_BURN_ERROR,
2575 BRASERO_BURN_ERROR_GENERAL,
2576 "%s", _("Only one track at a time can be checked"));
2577 return BRASERO_BURN_ERR;
2578 }
2579
2580 track = tracks->data;
2581
2582 /* if the input is a DISC, ask/check there is one and lock it (as dest) */
2583 if (BRASERO_IS_TRACK_IMAGE (track)) {
2584 /* make sure there is a disc. If not, ask one and lock it */
2585 result = brasero_burn_lock_checksum_media (self, error);
2586 if (result != BRASERO_BURN_OK)
2587 return result;
2588 }
2589
2590 brasero_burn_powermanagement (self, TRUE);
2591
2592 result = brasero_burn_check_real (self, track, error);
2593
2594 brasero_burn_powermanagement (self, FALSE);
2595
2596 if (result == BRASERO_BURN_OK)
2597 result = brasero_burn_unlock_medias (self, error);
2598 else
2599 brasero_burn_unlock_medias (self, NULL);
2600
2601 /* no need to check the result of the comparison, it's set in session */
2602
2603 if (result == BRASERO_BURN_OK)
2604 brasero_burn_action_changed_real (self,
2605 BRASERO_BURN_ACTION_FINISHED);
2606
2607 /* NOTE: unref session only AFTER drives are unlocked */
2608 priv->session = NULL;
2609 g_object_unref (session);
2610
2611 return result;
2612 }
2613
2614 static BraseroBurnResult
brasero_burn_same_src_dest_image(BraseroBurn * self,GError ** error)2615 brasero_burn_same_src_dest_image (BraseroBurn *self,
2616 GError **error)
2617 {
2618 BraseroBurnResult result;
2619 BraseroBurnPrivate *priv;
2620 BraseroTrackType *output = NULL;
2621
2622 /* we can't create a proper list of tasks here since we don't know the
2623 * dest media type yet. So we try to find an intermediate image type and
2624 * add it to the session as output */
2625 priv = BRASERO_BURN_PRIVATE (self);
2626
2627 /* get the first possible format */
2628 output = brasero_track_type_new ();
2629 result = brasero_burn_session_get_tmp_image_type_same_src_dest (priv->session, output);
2630 if (result != BRASERO_BURN_OK) {
2631 brasero_track_type_free (output);
2632 g_set_error (error,
2633 BRASERO_BURN_ERROR,
2634 BRASERO_BURN_ERROR_GENERAL,
2635 "%s", _("No format for the temporary image could be found"));
2636 return result;
2637 }
2638
2639 /* lock drive */
2640 result = brasero_burn_lock_src_media (self, error);
2641 if (result != BRASERO_BURN_OK)
2642 goto end;
2643
2644 /* run */
2645 result = brasero_burn_record_session (self, TRUE, output, error);
2646
2647 /* Check the results right now. If there was
2648 * an error the source medium will be dealt
2649 * with in brasero_burn_record () anyway
2650 * with brasero_burn_unlock_medias () */
2651 if (result != BRASERO_BURN_OK)
2652 goto end;
2653
2654 /* reset everything back to normal */
2655 result = brasero_burn_eject (self, priv->src, error);
2656 if (result != BRASERO_BURN_OK)
2657 goto end;
2658
2659 brasero_burn_unlock_src_media (self, NULL);
2660
2661 /* There should be (a) track(s) at the top of
2662 * the session stack so no need to create a
2663 * new one */
2664
2665 brasero_burn_action_changed_real (self, BRASERO_BURN_ACTION_FINISHED);
2666
2667 end:
2668
2669 if (output)
2670 brasero_track_type_free (output);
2671
2672 return result;
2673 }
2674
2675 static BraseroBurnResult
brasero_burn_same_src_dest_reload_medium(BraseroBurn * burn,GError ** error)2676 brasero_burn_same_src_dest_reload_medium (BraseroBurn *burn,
2677 GError **error)
2678 {
2679 BraseroBurnError berror;
2680 BraseroBurnPrivate *priv;
2681 BraseroBurnResult result;
2682 BraseroMedia required_media;
2683
2684 priv = BRASERO_BURN_PRIVATE (burn);
2685
2686 BRASERO_BURN_LOG ("Reloading medium after copy");
2687
2688 /* Now there is the problem of flags... This really is a special
2689 * case. we need to try to adjust the flags to the media type
2690 * just after a new one is detected. For example there could be
2691 * BURNPROOF/DUMMY whereas they are not supported for DVD+RW. So
2692 * we need to be lenient. */
2693
2694 /* Eject and ask the user to reload a disc */
2695 required_media = brasero_burn_session_get_required_media_type (priv->session);
2696 required_media &= (BRASERO_MEDIUM_WRITABLE|
2697 BRASERO_MEDIUM_CD|
2698 BRASERO_MEDIUM_DVD|
2699 BRASERO_MEDIUM_BD);
2700
2701 /* There is sometimes no way to determine which type of media is
2702 * required since some flags (that will be adjusted afterwards)
2703 * prevent to reach some media type like BURNPROOF and DVD+RW. */
2704 if (required_media == BRASERO_MEDIUM_NONE)
2705 required_media = BRASERO_MEDIUM_WRITABLE;
2706
2707 berror = BRASERO_BURN_WARNING_INSERT_AFTER_COPY;
2708
2709 again:
2710
2711 result = brasero_burn_ask_for_dest_media (burn,
2712 berror,
2713 required_media,
2714 error);
2715 if (result != BRASERO_BURN_OK)
2716 return result;
2717
2718 /* Note: we don't need to update the flags anymore
2719 * as they are updated in brasero_burn_run_tasks ()
2720 * anyway. */
2721
2722 if (result != BRASERO_BURN_OK) {
2723 /* Tell the user his/her disc is not supported and reload */
2724 berror = BRASERO_BURN_ERROR_MEDIUM_INVALID;
2725 goto again;
2726 }
2727
2728 result = brasero_burn_lock_dest_media (burn, &berror, error);
2729 if (result == BRASERO_BURN_CANCEL)
2730 return result;
2731
2732 if (result != BRASERO_BURN_OK) {
2733 /* Tell the user his/her disc is not supported and reload */
2734 goto again;
2735 }
2736
2737 return BRASERO_BURN_OK;
2738 }
2739
2740 /**
2741 * brasero_burn_record:
2742 * @burn: a #BraseroBurn
2743 * @session: a #BraseroBurnSession
2744 * @error: a #GError
2745 *
2746 * Burns or creates a disc image according to the parameters
2747 * set in @session.
2748 *
2749 * Return value: a #BraseroBurnResult. The result of the operation.
2750 * BRASERO_BURN_OK if it was successful.
2751 **/
2752
2753 BraseroBurnResult
brasero_burn_record(BraseroBurn * burn,BraseroBurnSession * session,GError ** error)2754 brasero_burn_record (BraseroBurn *burn,
2755 BraseroBurnSession *session,
2756 GError **error)
2757 {
2758 BraseroTrackType *type = NULL;
2759 BraseroBurnResult result;
2760 BraseroBurnPrivate *priv;
2761
2762 g_return_val_if_fail (BRASERO_IS_BURN (burn), BRASERO_BURN_ERR);
2763 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
2764
2765 priv = BRASERO_BURN_PRIVATE (burn);
2766
2767 /* make sure we're ready */
2768 if (brasero_burn_session_get_status (session, NULL) != BRASERO_BURN_OK)
2769 return BRASERO_BURN_ERR;
2770
2771 g_object_ref (session);
2772 priv->session = session;
2773
2774 brasero_burn_powermanagement (burn, TRUE);
2775
2776 /* say to the whole world we started */
2777 brasero_burn_action_changed_real (burn, BRASERO_BURN_ACTION_PREPARING);
2778
2779 if (brasero_burn_session_same_src_dest_drive (session)) {
2780 /* This is a special case */
2781 result = brasero_burn_same_src_dest_image (burn, error);
2782 if (result != BRASERO_BURN_OK)
2783 goto end;
2784
2785 result = brasero_burn_same_src_dest_reload_medium (burn, error);
2786 if (result != BRASERO_BURN_OK)
2787 goto end;
2788 }
2789 else if (!brasero_burn_session_is_dest_file (session)) {
2790 BraseroBurnError berror = BRASERO_BURN_ERROR_NONE;
2791
2792 /* do some drive locking quite early to make sure we have a
2793 * media in the drive so that we'll have all the necessary
2794 * information */
2795 result = brasero_burn_lock_dest_media (burn, &berror, error);
2796 while (result == BRASERO_BURN_NEED_RELOAD) {
2797 BraseroMedia required_media;
2798
2799 required_media = brasero_burn_session_get_required_media_type (priv->session);
2800 if (required_media == BRASERO_MEDIUM_NONE)
2801 required_media = BRASERO_MEDIUM_WRITABLE;
2802
2803 result = brasero_burn_ask_for_dest_media (burn,
2804 berror,
2805 required_media,
2806 error);
2807 if (result != BRASERO_BURN_OK)
2808 goto end;
2809
2810 result = brasero_burn_lock_dest_media (burn, &berror, error);
2811 }
2812
2813 if (result != BRASERO_BURN_OK)
2814 goto end;
2815 }
2816
2817 type = brasero_track_type_new ();
2818 brasero_burn_session_get_input_type (session, type);
2819 if (brasero_track_type_get_has_medium (type)) {
2820 result = brasero_burn_lock_src_media (burn, error);
2821 if (result != BRASERO_BURN_OK)
2822 goto end;
2823 }
2824
2825 /* burn the session except if dummy session */
2826 result = brasero_burn_record_session (burn, TRUE, NULL, error);
2827
2828 end:
2829
2830 brasero_track_type_free (type);
2831
2832 if (result == BRASERO_BURN_OK)
2833 result = brasero_burn_unlock_medias (burn, error);
2834 else
2835 brasero_burn_unlock_medias (burn, NULL);
2836
2837 if (error && (*error) == NULL
2838 && (result == BRASERO_BURN_NOT_READY
2839 || result == BRASERO_BURN_NOT_SUPPORTED
2840 || result == BRASERO_BURN_RUNNING
2841 || result == BRASERO_BURN_NOT_RUNNING)) {
2842 BRASERO_BURN_LOG ("Internal error with result %i", result);
2843 g_set_error (error,
2844 BRASERO_BURN_ERROR,
2845 BRASERO_BURN_ERROR_GENERAL,
2846 "%s", _("An internal error occurred"));
2847 }
2848
2849 if (result == BRASERO_BURN_CANCEL) {
2850 BRASERO_BURN_DEBUG (burn, "Session cancelled by user");
2851 }
2852 else if (result != BRASERO_BURN_OK) {
2853 if (error && (*error)) {
2854 BRASERO_BURN_DEBUG (burn,
2855 "Session error : %s",
2856 (*error)->message);
2857 }
2858 else
2859 BRASERO_BURN_DEBUG (burn, "Session error : unknown");
2860 }
2861 else {
2862 BRASERO_BURN_DEBUG (burn, "Session successfully finished");
2863 brasero_burn_action_changed_real (burn,
2864 BRASERO_BURN_ACTION_FINISHED);
2865 }
2866
2867 brasero_burn_powermanagement (burn, FALSE);
2868
2869 /* release session */
2870 g_object_unref (priv->session);
2871 priv->session = NULL;
2872
2873 return result;
2874 }
2875
2876 static BraseroBurnResult
brasero_burn_blank_real(BraseroBurn * burn,GError ** error)2877 brasero_burn_blank_real (BraseroBurn *burn, GError **error)
2878 {
2879 BraseroBurnResult result;
2880 BraseroBurnPrivate *priv;
2881
2882 priv = BRASERO_BURN_PRIVATE (burn);
2883
2884 priv->task = brasero_burn_caps_new_blanking_task (priv->caps,
2885 priv->session,
2886 error);
2887 if (!priv->task)
2888 return BRASERO_BURN_NOT_SUPPORTED;
2889
2890 g_signal_connect (priv->task,
2891 "progress-changed",
2892 G_CALLBACK (brasero_burn_progress_changed),
2893 burn);
2894 g_signal_connect (priv->task,
2895 "action-changed",
2896 G_CALLBACK (brasero_burn_action_changed),
2897 burn);
2898
2899 result = brasero_burn_run_eraser (burn, error);
2900 g_object_unref (priv->task);
2901 priv->task = NULL;
2902
2903 return result;
2904 }
2905
2906 /**
2907 * brasero_burn_blank:
2908 * @burn: a #BraseroBurn
2909 * @session: a #BraseroBurnSession
2910 * @error: a #GError
2911 *
2912 * Blanks a medium according to the parameters
2913 * set in @session. The medium must be inserted in the #BraseroDrive
2914 * set with brasero_burn_session_set_burner ().
2915 *
2916 * Return value: a #BraseroBurnResult. The result of the operation.
2917 * BRASERO_BURN_OK if it was successful.
2918 **/
2919
2920 BraseroBurnResult
brasero_burn_blank(BraseroBurn * burn,BraseroBurnSession * session,GError ** error)2921 brasero_burn_blank (BraseroBurn *burn,
2922 BraseroBurnSession *session,
2923 GError **error)
2924 {
2925 BraseroBurnPrivate *priv;
2926 BraseroBurnResult result;
2927 GError *ret_error = NULL;
2928
2929 g_return_val_if_fail (burn != NULL, BRASERO_BURN_ERR);
2930 g_return_val_if_fail (session != NULL, BRASERO_BURN_ERR);
2931
2932 priv = BRASERO_BURN_PRIVATE (burn);
2933
2934 g_object_ref (session);
2935 priv->session = session;
2936
2937 brasero_burn_powermanagement (burn, TRUE);
2938
2939 /* we wait for the insertion of a media and lock it */
2940 result = brasero_burn_lock_rewritable_media (burn, error);
2941 if (result != BRASERO_BURN_OK)
2942 goto end;
2943
2944 result = brasero_burn_blank_real (burn, &ret_error);
2945 while (result == BRASERO_BURN_ERR &&
2946 ret_error &&
2947 ret_error->code == BRASERO_BURN_ERROR_MEDIUM_NOT_REWRITABLE) {
2948 g_error_free (ret_error);
2949 ret_error = NULL;
2950
2951 result = brasero_burn_ask_for_dest_media (burn,
2952 BRASERO_BURN_ERROR_MEDIUM_NOT_REWRITABLE,
2953 BRASERO_MEDIUM_REWRITABLE|
2954 BRASERO_MEDIUM_HAS_DATA,
2955 error);
2956 if (result != BRASERO_BURN_OK)
2957 break;
2958
2959 result = brasero_burn_lock_rewritable_media (burn, error);
2960 if (result != BRASERO_BURN_OK)
2961 break;
2962
2963 result = brasero_burn_blank_real (burn, &ret_error);
2964 }
2965
2966 end:
2967 if (ret_error)
2968 g_propagate_error (error, ret_error);
2969
2970 if (result == BRASERO_BURN_OK && !ret_error)
2971 result = brasero_burn_unlock_medias (burn, error);
2972 else
2973 brasero_burn_unlock_medias (burn, NULL);
2974
2975 if (result == BRASERO_BURN_OK)
2976 brasero_burn_action_changed_real (burn, BRASERO_BURN_ACTION_FINISHED);
2977
2978 brasero_burn_powermanagement (burn, FALSE);
2979
2980 /* release session */
2981 g_object_unref (priv->session);
2982 priv->session = NULL;
2983
2984 return result;
2985 }
2986
2987 /**
2988 * brasero_burn_cancel:
2989 * @burn: a #BraseroBurn
2990 * @protect: a #gboolean
2991 *
2992 * Cancels any ongoing operation. If @protect is TRUE then
2993 * cancellation will not take place for a "critical" task, a task whose interruption
2994 * could damage the medium or the drive.
2995 *
2996 * Return value: a #BraseroBurnResult. The result of the operation.
2997 * BRASERO_BURN_OK if it was successful.
2998 **/
2999
3000 BraseroBurnResult
brasero_burn_cancel(BraseroBurn * burn,gboolean protect)3001 brasero_burn_cancel (BraseroBurn *burn, gboolean protect)
3002 {
3003 BraseroBurnResult result = BRASERO_BURN_OK;
3004 BraseroBurnPrivate *priv;
3005
3006 g_return_val_if_fail (BRASERO_BURN (burn), BRASERO_BURN_ERR);
3007
3008 priv = BRASERO_BURN_PRIVATE (burn);
3009
3010 if (priv->timeout_id) {
3011 g_source_remove (priv->timeout_id);
3012 priv->timeout_id = 0;
3013 }
3014
3015 if (priv->sleep_loop) {
3016 g_main_loop_quit (priv->sleep_loop);
3017 priv->sleep_loop = NULL;
3018 }
3019
3020 if (priv->dest)
3021 brasero_drive_cancel_current_operation (priv->dest);
3022
3023 if (priv->src)
3024 brasero_drive_cancel_current_operation (priv->src);
3025
3026 if (priv->task && brasero_task_is_running (priv->task))
3027 result = brasero_task_cancel (priv->task, protect);
3028
3029 return result;
3030 }
3031
3032 static void
brasero_burn_finalize(GObject * object)3033 brasero_burn_finalize (GObject *object)
3034 {
3035 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (object);
3036
3037 if (priv->timeout_id) {
3038 g_source_remove (priv->timeout_id);
3039 priv->timeout_id = 0;
3040 }
3041
3042 if (priv->sleep_loop) {
3043 g_main_loop_quit (priv->sleep_loop);
3044 priv->sleep_loop = NULL;
3045 }
3046
3047 if (priv->task) {
3048 g_object_unref (priv->task);
3049 priv->task = NULL;
3050 }
3051
3052 if (priv->session) {
3053 g_object_unref (priv->session);
3054 priv->session = NULL;
3055 }
3056
3057 if (priv->caps)
3058 g_object_unref (priv->caps);
3059
3060 G_OBJECT_CLASS (parent_class)->finalize (object);
3061 }
3062
3063 static void
brasero_burn_class_init(BraseroBurnClass * klass)3064 brasero_burn_class_init (BraseroBurnClass *klass)
3065 {
3066 GObjectClass *object_class = G_OBJECT_CLASS (klass);
3067
3068 g_type_class_add_private (klass, sizeof (BraseroBurnPrivate));
3069
3070 parent_class = g_type_class_peek_parent (klass);
3071 object_class->finalize = brasero_burn_finalize;
3072
3073 brasero_burn_signals [ASK_DISABLE_JOLIET_SIGNAL] =
3074 g_signal_new ("disable_joliet",
3075 G_TYPE_FROM_CLASS (klass),
3076 G_SIGNAL_RUN_LAST,
3077 G_STRUCT_OFFSET (BraseroBurnClass,
3078 ask_disable_joliet),
3079 NULL, NULL,
3080 brasero_marshal_INT__VOID,
3081 G_TYPE_INT, 0);
3082 brasero_burn_signals [WARN_DATA_LOSS_SIGNAL] =
3083 g_signal_new ("warn_data_loss",
3084 G_TYPE_FROM_CLASS (klass),
3085 G_SIGNAL_RUN_LAST,
3086 G_STRUCT_OFFSET (BraseroBurnClass,
3087 warn_data_loss),
3088 NULL, NULL,
3089 brasero_marshal_INT__VOID,
3090 G_TYPE_INT, 0);
3091 brasero_burn_signals [WARN_PREVIOUS_SESSION_LOSS_SIGNAL] =
3092 g_signal_new ("warn_previous_session_loss",
3093 G_TYPE_FROM_CLASS (klass),
3094 G_SIGNAL_RUN_LAST,
3095 G_STRUCT_OFFSET (BraseroBurnClass,
3096 warn_previous_session_loss),
3097 NULL, NULL,
3098 brasero_marshal_INT__VOID,
3099 G_TYPE_INT, 0);
3100 brasero_burn_signals [WARN_AUDIO_TO_APPENDABLE_SIGNAL] =
3101 g_signal_new ("warn_audio_to_appendable",
3102 G_TYPE_FROM_CLASS (klass),
3103 G_SIGNAL_RUN_LAST,
3104 G_STRUCT_OFFSET (BraseroBurnClass,
3105 warn_audio_to_appendable),
3106 NULL, NULL,
3107 brasero_marshal_INT__VOID,
3108 G_TYPE_INT, 0);
3109 brasero_burn_signals [WARN_REWRITABLE_SIGNAL] =
3110 g_signal_new ("warn_rewritable",
3111 G_TYPE_FROM_CLASS (klass),
3112 G_SIGNAL_RUN_LAST,
3113 G_STRUCT_OFFSET (BraseroBurnClass,
3114 warn_rewritable),
3115 NULL, NULL,
3116 brasero_marshal_INT__VOID,
3117 G_TYPE_INT, 0);
3118 brasero_burn_signals [INSERT_MEDIA_REQUEST_SIGNAL] =
3119 g_signal_new ("insert_media",
3120 G_TYPE_FROM_CLASS (klass),
3121 G_SIGNAL_RUN_LAST,
3122 G_STRUCT_OFFSET (BraseroBurnClass,
3123 insert_media_request),
3124 NULL, NULL,
3125 brasero_marshal_INT__OBJECT_INT_INT,
3126 G_TYPE_INT,
3127 3,
3128 BRASERO_TYPE_DRIVE,
3129 G_TYPE_INT,
3130 G_TYPE_INT);
3131 brasero_burn_signals [LOCATION_REQUEST_SIGNAL] =
3132 g_signal_new ("location-request",
3133 G_TYPE_FROM_CLASS (klass),
3134 G_SIGNAL_RUN_LAST,
3135 G_STRUCT_OFFSET (BraseroBurnClass,
3136 location_request),
3137 NULL, NULL,
3138 brasero_marshal_INT__POINTER_BOOLEAN,
3139 G_TYPE_INT,
3140 2,
3141 G_TYPE_POINTER,
3142 G_TYPE_INT);
3143 brasero_burn_signals [PROGRESS_CHANGED_SIGNAL] =
3144 g_signal_new ("progress_changed",
3145 G_TYPE_FROM_CLASS (klass),
3146 G_SIGNAL_RUN_LAST,
3147 G_STRUCT_OFFSET (BraseroBurnClass,
3148 progress_changed),
3149 NULL, NULL,
3150 brasero_marshal_VOID__DOUBLE_DOUBLE_LONG,
3151 G_TYPE_NONE,
3152 3,
3153 G_TYPE_DOUBLE,
3154 G_TYPE_DOUBLE,
3155 G_TYPE_LONG);
3156 brasero_burn_signals [ACTION_CHANGED_SIGNAL] =
3157 g_signal_new ("action_changed",
3158 G_TYPE_FROM_CLASS (klass),
3159 G_SIGNAL_RUN_LAST,
3160 G_STRUCT_OFFSET (BraseroBurnClass,
3161 action_changed),
3162 NULL, NULL,
3163 g_cclosure_marshal_VOID__INT,
3164 G_TYPE_NONE,
3165 1,
3166 G_TYPE_INT);
3167 brasero_burn_signals [DUMMY_SUCCESS_SIGNAL] =
3168 g_signal_new ("dummy_success",
3169 G_TYPE_FROM_CLASS (klass),
3170 G_SIGNAL_RUN_LAST,
3171 G_STRUCT_OFFSET (BraseroBurnClass,
3172 dummy_success),
3173 NULL, NULL,
3174 brasero_marshal_INT__VOID,
3175 G_TYPE_INT, 0);
3176 brasero_burn_signals [EJECT_FAILURE_SIGNAL] =
3177 g_signal_new ("eject_failure",
3178 G_TYPE_FROM_CLASS (klass),
3179 G_SIGNAL_RUN_LAST,
3180 G_STRUCT_OFFSET (BraseroBurnClass,
3181 eject_failure),
3182 NULL, NULL,
3183 brasero_marshal_INT__OBJECT,
3184 G_TYPE_INT, 1,
3185 BRASERO_TYPE_DRIVE);
3186 brasero_burn_signals [BLANK_FAILURE_SIGNAL] =
3187 g_signal_new ("blank_failure",
3188 G_TYPE_FROM_CLASS (klass),
3189 G_SIGNAL_RUN_LAST,
3190 G_STRUCT_OFFSET (BraseroBurnClass,
3191 blank_failure),
3192 NULL, NULL,
3193 brasero_marshal_INT__VOID,
3194 G_TYPE_INT, 0,
3195 G_TYPE_NONE);
3196 brasero_burn_signals [INSTALL_MISSING_SIGNAL] =
3197 g_signal_new ("install_missing",
3198 G_TYPE_FROM_CLASS (klass),
3199 G_SIGNAL_RUN_LAST,
3200 G_STRUCT_OFFSET (BraseroBurnClass,
3201 install_missing),
3202 NULL, NULL,
3203 brasero_marshal_INT__INT_STRING,
3204 G_TYPE_INT, 2,
3205 G_TYPE_INT,
3206 G_TYPE_STRING);
3207 }
3208
3209 static void
brasero_burn_init(BraseroBurn * obj)3210 brasero_burn_init (BraseroBurn *obj)
3211 {
3212 BraseroBurnPrivate *priv = BRASERO_BURN_PRIVATE (obj);
3213
3214 priv->caps = brasero_burn_caps_get_default ();
3215 }
3216