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 <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <errno.h>
41
42 #include <glib.h>
43 #include <glib-object.h>
44 #include <glib/gi18n-lib.h>
45 #include <gmodule.h>
46
47 #include <libburn/libburn.h>
48
49 #include "brasero-units.h"
50 #include "burn-job.h"
51 #include "burn-debug.h"
52 #include "brasero-plugin-registration.h"
53 #include "burn-libburn-common.h"
54 #include "burn-libburnia.h"
55 #include "brasero-track-image.h"
56 #include "brasero-track-stream.h"
57
58
59 #define BRASERO_TYPE_LIBBURN (brasero_libburn_get_type ())
60 #define BRASERO_LIBBURN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBBURN, BraseroLibburn))
61 #define BRASERO_LIBBURN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
62 #define BRASERO_IS_LIBBURN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBBURN))
63 #define BRASERO_IS_LIBBURN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBBURN))
64 #define BRASERO_LIBBURN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
65
66 BRASERO_PLUGIN_BOILERPLATE (BraseroLibburn, brasero_libburn, BRASERO_TYPE_JOB, BraseroJob);
67
68 #define BRASERO_PVD_SIZE 32ULL * 2048ULL
69
70 struct _BraseroLibburnPrivate {
71 BraseroLibburnCtx *ctx;
72
73 /* This buffer is used to capture Primary Volume Descriptor for
74 * for overwrite media so as to "grow" the latter. */
75 unsigned char *pvd;
76
77 guint sig_handler:1;
78 };
79 typedef struct _BraseroLibburnPrivate BraseroLibburnPrivate;
80
81 #define BRASERO_LIBBURN_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnPrivate))
82
83 /**
84 * taken from scsi-get-configuration.h
85 */
86
87 typedef enum {
88 BRASERO_SCSI_PROF_DVD_RW_RESTRICTED = 0x0013,
89 BRASERO_SCSI_PROF_DVD_RW_PLUS = 0x001A,
90 } BraseroScsiProfile;
91
92 static GObjectClass *parent_class = NULL;
93
94 struct _BraseroLibburnSrcData {
95 int fd;
96 off_t size;
97
98 /* That's for the primary volume descriptor used for overwrite media */
99 int pvd_size; /* in blocks */
100 unsigned char *pvd;
101
102 int read_pvd:1;
103 };
104 typedef struct _BraseroLibburnSrcData BraseroLibburnSrcData;
105
106 static void
brasero_libburn_src_free_data(struct burn_source * src)107 brasero_libburn_src_free_data (struct burn_source *src)
108 {
109 BraseroLibburnSrcData *data;
110
111 data = src->data;
112 close (data->fd);
113 g_free (data);
114 }
115
116 static off_t
brasero_libburn_src_get_size(struct burn_source * src)117 brasero_libburn_src_get_size (struct burn_source *src)
118 {
119 BraseroLibburnSrcData *data;
120
121 data = src->data;
122 return data->size;
123 }
124
125 static int
brasero_libburn_src_set_size(struct burn_source * src,off_t size)126 brasero_libburn_src_set_size (struct burn_source *src,
127 off_t size)
128 {
129 BraseroLibburnSrcData *data;
130
131 data = src->data;
132 data->size = size;
133 return 1;
134 }
135
136 /**
137 * This is a copy from burn-volume.c
138 */
139
140 struct _BraseroVolDesc {
141 guchar type;
142 gchar id [5];
143 guchar version;
144 };
145 typedef struct _BraseroVolDesc BraseroVolDesc;
146
147 static int
brasero_libburn_src_read_xt(struct burn_source * src,unsigned char * buffer,int size)148 brasero_libburn_src_read_xt (struct burn_source *src,
149 unsigned char *buffer,
150 int size)
151 {
152 int total;
153 BraseroLibburnSrcData *data;
154
155 data = src->data;
156
157 total = 0;
158 while (total < size) {
159 int bytes;
160
161 bytes = read (data->fd, buffer + total, size - total);
162 if (bytes < 0)
163 return -1;
164
165 if (!bytes)
166 break;
167
168 total += bytes;
169 }
170
171 /* copy the primary volume descriptor if a buffer is provided */
172 if (data->pvd
173 && !data->read_pvd
174 && data->pvd_size < BRASERO_PVD_SIZE) {
175 unsigned char *current_pvd;
176 int i;
177
178 current_pvd = data->pvd + data->pvd_size;
179
180 /* read volume descriptors until we reach the end of the
181 * buffer or find a volume descriptor set end. */
182 for (i = 0; (i << 11) < size && data->pvd_size + (i << 11) < BRASERO_PVD_SIZE; i ++) {
183 BraseroVolDesc *desc;
184
185 /* No need to check the first 16 blocks */
186 if ((data->pvd_size >> 11) + i < 16)
187 continue;
188
189 desc = (BraseroVolDesc *) (buffer + sizeof (BraseroVolDesc) * i);
190 if (desc->type == 255) {
191 data->read_pvd = 1;
192 BRASERO_BURN_LOG ("found volume descriptor set end");
193 break;
194 }
195 }
196
197 memcpy (current_pvd, buffer, i << 11);
198 data->pvd_size += i << 11;
199 }
200
201 return total;
202 }
203
204 static struct burn_source *
brasero_libburn_create_fd_source(int fd,gint64 size,unsigned char * pvd)205 brasero_libburn_create_fd_source (int fd,
206 gint64 size,
207 unsigned char *pvd)
208 {
209 struct burn_source *src;
210 BraseroLibburnSrcData *data;
211
212 data = g_new0 (BraseroLibburnSrcData, 1);
213 data->fd = fd;
214 data->size = size;
215 data->pvd = pvd;
216
217 /* FIXME: this could be wrapped into a fifo source to get a smoother
218 * data delivery. But that means another thread ... */
219 src = g_new0 (struct burn_source, 1);
220 src->version = 1;
221 src->refcount = 1;
222 src->read_xt = brasero_libburn_src_read_xt;
223 src->get_size = brasero_libburn_src_get_size;
224 src->set_size = brasero_libburn_src_set_size;
225 src->free_data = brasero_libburn_src_free_data;
226 src->data = data;
227
228 return src;
229 }
230
231 static BraseroBurnResult
brasero_libburn_add_track(struct burn_session * session,struct burn_track * track,struct burn_source * src,gint mode,GError ** error)232 brasero_libburn_add_track (struct burn_session *session,
233 struct burn_track *track,
234 struct burn_source *src,
235 gint mode,
236 GError **error)
237 {
238 if (burn_track_set_source (track, src) != BURN_SOURCE_OK) {
239 g_set_error (error,
240 BRASERO_BURN_ERROR,
241 BRASERO_BURN_ERROR_GENERAL,
242 _("libburn track could not be created"));
243 return BRASERO_BURN_ERR;
244 }
245
246 if (!burn_session_add_track (session, track, BURN_POS_END)) {
247 g_set_error (error,
248 BRASERO_BURN_ERROR,
249 BRASERO_BURN_ERROR_GENERAL,
250 _("libburn track could not be created"));
251 return BRASERO_BURN_ERR;
252 }
253
254 return BRASERO_BURN_OK;
255 }
256
257 static BraseroBurnResult
brasero_libburn_add_fd_track(struct burn_session * session,int fd,gint mode,gint64 size,unsigned char * pvd,GError ** error)258 brasero_libburn_add_fd_track (struct burn_session *session,
259 int fd,
260 gint mode,
261 gint64 size,
262 unsigned char *pvd,
263 GError **error)
264 {
265 struct burn_source *src;
266 struct burn_track *track;
267 BraseroBurnResult result;
268
269 track = burn_track_create ();
270 burn_track_define_data (track, 0, 0, 0, mode);
271
272 src = brasero_libburn_create_fd_source (fd, size, pvd);
273 result = brasero_libburn_add_track (session, track, src, mode, error);
274
275 burn_source_free (src);
276 burn_track_free (track);
277
278 return result;
279 }
280
281 static BraseroBurnResult
brasero_libburn_add_file_track(struct burn_session * session,const gchar * path,gint mode,off_t size,unsigned char * pvd,GError ** error)282 brasero_libburn_add_file_track (struct burn_session *session,
283 const gchar *path,
284 gint mode,
285 off_t size,
286 unsigned char *pvd,
287 GError **error)
288 {
289 int fd;
290
291 fd = open (path, O_RDONLY);
292 if (fd == -1) {
293 g_set_error (error,
294 BRASERO_BURN_ERROR,
295 BRASERO_BURN_ERROR_GENERAL,
296 "%s",
297 g_strerror (errno));
298 return BRASERO_BURN_ERR;
299 }
300
301 return brasero_libburn_add_fd_track (session, fd, mode, size, pvd, error);
302 }
303
304 static BraseroBurnResult
brasero_libburn_setup_session_fd(BraseroLibburn * self,struct burn_session * session,GError ** error)305 brasero_libburn_setup_session_fd (BraseroLibburn *self,
306 struct burn_session *session,
307 GError **error)
308 {
309 int fd;
310 goffset bytes = 0;
311 BraseroLibburnPrivate *priv;
312 BraseroTrackType *type = NULL;
313 BraseroBurnResult result = BRASERO_BURN_OK;
314
315 priv = BRASERO_LIBBURN_PRIVATE (self);
316
317 brasero_job_get_fd_in (BRASERO_JOB (self), &fd);
318
319 /* need to find out what type of track the imager will output */
320 type = brasero_track_type_new ();
321 brasero_job_get_input_type (BRASERO_JOB (self), type);
322
323 if (brasero_track_type_get_has_image (type)) {
324 gint mode;
325
326 /* FIXME: implement other IMAGE types */
327 if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_BIN)
328 mode = BURN_MODE1;
329 else
330 mode = BURN_MODE1|BURN_MODE_RAW|BURN_SUBCODE_R96;
331
332 brasero_track_type_free (type);
333
334 brasero_job_get_session_output_size (BRASERO_JOB (self),
335 NULL,
336 &bytes);
337
338 result = brasero_libburn_add_fd_track (session,
339 fd,
340 mode,
341 bytes,
342 priv->pvd,
343 error);
344 }
345 else if (brasero_track_type_get_has_stream (type)) {
346 GSList *tracks;
347 guint64 length = 0;
348
349 brasero_track_type_free (type);
350
351 brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
352 for (; tracks; tracks = tracks->next) {
353 BraseroTrack *track;
354
355 track = tracks->data;
356 brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
357 bytes = BRASERO_DURATION_TO_BYTES (length);
358
359 /* we dup the descriptor so the same
360 * will be shared by all tracks */
361 result = brasero_libburn_add_fd_track (session,
362 dup (fd),
363 BURN_AUDIO,
364 bytes,
365 NULL,
366 error);
367 if (result != BRASERO_BURN_OK)
368 return result;
369 }
370 }
371 else
372 BRASERO_JOB_NOT_SUPPORTED (self);
373
374 return result;
375 }
376
377 static BraseroBurnResult
brasero_libburn_setup_session_file(BraseroLibburn * self,struct burn_session * session,GError ** error)378 brasero_libburn_setup_session_file (BraseroLibburn *self,
379 struct burn_session *session,
380 GError **error)
381 {
382 BraseroLibburnPrivate *priv;
383 BraseroBurnResult result;
384 GSList *tracks = NULL;
385
386 priv = BRASERO_LIBBURN_PRIVATE (self);
387
388 /* create the track(s) */
389 result = BRASERO_BURN_OK;
390 brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
391 for (; tracks; tracks = tracks->next) {
392 BraseroTrack *track;
393
394 track = tracks->data;
395 if (BRASERO_IS_TRACK_STREAM (track)) {
396 gchar *audiopath;
397 guint64 size;
398
399 audiopath = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
400 brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &size);
401 size = BRASERO_DURATION_TO_BYTES (size);
402
403 result = brasero_libburn_add_file_track (session,
404 audiopath,
405 BURN_AUDIO,
406 size,
407 NULL,
408 error);
409 if (result != BRASERO_BURN_OK)
410 break;
411 }
412 else if (BRASERO_IS_TRACK_IMAGE (track)) {
413 BraseroImageFormat format;
414 gchar *imagepath;
415 goffset bytes;
416 gint mode;
417
418 format = brasero_track_image_get_format (BRASERO_TRACK_IMAGE (track));
419 if (format == BRASERO_IMAGE_FORMAT_BIN) {
420 mode = BURN_MODE1;
421 imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
422 }
423 else if (format == BRASERO_IMAGE_FORMAT_NONE) {
424 mode = BURN_MODE1;
425 imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
426 }
427 else
428 BRASERO_JOB_NOT_SUPPORTED (self);
429
430 if (!imagepath)
431 return BRASERO_BURN_ERR;
432
433 result = brasero_track_get_size (track,
434 NULL,
435 &bytes);
436 if (result != BRASERO_BURN_OK)
437 return BRASERO_BURN_ERR;
438
439 result = brasero_libburn_add_file_track (session,
440 imagepath,
441 mode,
442 bytes,
443 priv->pvd,
444 error);
445 g_free (imagepath);
446 }
447 else
448 BRASERO_JOB_NOT_SUPPORTED (self);
449 }
450
451 return result;
452 }
453
454 static BraseroBurnResult
brasero_libburn_create_disc(BraseroLibburn * self,struct burn_disc ** retval,GError ** error)455 brasero_libburn_create_disc (BraseroLibburn *self,
456 struct burn_disc **retval,
457 GError **error)
458 {
459 struct burn_disc *disc;
460 BraseroBurnResult result;
461 struct burn_session *session;
462
463 /* set the source image */
464 disc = burn_disc_create ();
465
466 /* create the session */
467 session = burn_session_create ();
468 burn_disc_add_session (disc, session, BURN_POS_END);
469 burn_session_free (session);
470
471 if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK)
472 result = brasero_libburn_setup_session_fd (self, session, error);
473 else
474 result = brasero_libburn_setup_session_file (self, session, error);
475
476 if (result != BRASERO_BURN_OK) {
477 burn_disc_free (disc);
478 return result;
479 }
480
481 *retval = disc;
482 return result;
483 }
484
485 static BraseroBurnResult
brasero_libburn_start_record(BraseroLibburn * self,GError ** error)486 brasero_libburn_start_record (BraseroLibburn *self,
487 GError **error)
488 {
489 guint64 rate;
490 goffset blocks = 0;
491 BraseroMedia media;
492 BraseroBurnFlag flags;
493 BraseroBurnResult result;
494 BraseroLibburnPrivate *priv;
495 struct burn_write_opts *opts;
496 gchar reason [BURN_REASONS_LEN];
497
498 priv = BRASERO_LIBBURN_PRIVATE (self);
499
500 /* if appending a DVD+-RW get PVD */
501 brasero_job_get_flags (BRASERO_JOB (self), &flags);
502 brasero_job_get_media (BRASERO_JOB (self), &media);
503
504 if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND)
505 && BRASERO_MEDIUM_RANDOM_WRITABLE (media)
506 && (media & BRASERO_MEDIUM_HAS_DATA))
507 priv->pvd = g_new0 (unsigned char, BRASERO_PVD_SIZE);
508
509 result = brasero_libburn_create_disc (self, &priv->ctx->disc, error);
510 if (result != BRASERO_BURN_OK)
511 return result;
512
513 /* Note: we don't need to call burn_drive_get_status nor
514 * burn_disc_get_status since we took care of the disc
515 * checking thing earlier ourselves. Now there is a proper
516 * disc and tray is locked. */
517 opts = burn_write_opts_new (priv->ctx->drive);
518
519 /* only turn this on for CDs */
520 if ((media & BRASERO_MEDIUM_CD) != 0)
521 burn_write_opts_set_perform_opc (opts, 0);
522 else
523 burn_write_opts_set_perform_opc (opts, 0);
524
525 if (flags & BRASERO_BURN_FLAG_DAO)
526 burn_write_opts_set_write_type (opts,
527 BURN_WRITE_SAO,
528 BURN_BLOCK_SAO);
529 else {
530 burn_write_opts_set_write_type (opts,
531 BURN_WRITE_TAO,
532 BURN_BLOCK_MODE1);
533
534 /* we also set the start block to write from if MERGE is set.
535 * That only for random writable media; for other media libburn
536 * handles all by himself where to start writing. */
537 if (BRASERO_MEDIUM_RANDOM_WRITABLE (media)
538 && (flags & BRASERO_BURN_FLAG_MERGE)) {
539 goffset address = 0;
540
541 brasero_job_get_next_writable_address (BRASERO_JOB (self), &address);
542
543 BRASERO_JOB_LOG (self, "Starting to write at block = %lli and byte %lli", address, address * 2048);
544 burn_write_opts_set_start_byte (opts, address * 2048);
545 }
546 }
547
548 if (!BRASERO_MEDIUM_RANDOM_WRITABLE (media)) {
549 BRASERO_JOB_LOG (BRASERO_JOB (self), "Setting multi %i", (flags & BRASERO_BURN_FLAG_MULTI) != 0);
550 burn_write_opts_set_multi (opts, (flags & BRASERO_BURN_FLAG_MULTI) != 0);
551 }
552
553 burn_write_opts_set_underrun_proof (opts, (flags & BRASERO_BURN_FLAG_BURNPROOF) != 0);
554 BRASERO_JOB_LOG (BRASERO_JOB (self), "Setting burnproof %i", (flags & BRASERO_BURN_FLAG_BURNPROOF) != 0);
555
556 burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY) != 0);
557 BRASERO_JOB_LOG (BRASERO_JOB (self), "Setting dummy %i", (flags & BRASERO_BURN_FLAG_DUMMY) != 0);
558
559 brasero_job_get_rate (BRASERO_JOB (self), &rate);
560 burn_drive_set_speed (priv->ctx->drive, rate, 0);
561
562 if (burn_precheck_write (opts, priv->ctx->disc, reason, 0) < 1) {
563 BRASERO_JOB_LOG (BRASERO_JOB (self), "Precheck failed %s", reason);
564 g_set_error (error,
565 BRASERO_BURN_ERROR,
566 BRASERO_BURN_ERROR_GENERAL,
567 "%s",
568 reason);
569 return BRASERO_BURN_ERR;
570 }
571
572 /* If we're writing to a disc remember that the session can't be under
573 * 300 sectors (= 614400 bytes) */
574 brasero_job_get_session_output_size (BRASERO_JOB (self), &blocks, NULL);
575 if (blocks < 300)
576 brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
577 300L - blocks,
578 614400L - blocks * 2048);
579
580 if (!priv->sig_handler) {
581 burn_set_signal_handling ("brasero", NULL, 0);
582 priv->sig_handler = 1;
583 }
584
585 burn_disc_write (opts, priv->ctx->disc);
586 burn_write_opts_free (opts);
587
588 return BRASERO_BURN_OK;
589 }
590
591 static BraseroBurnResult
brasero_libburn_start_erase(BraseroLibburn * self,GError ** error)592 brasero_libburn_start_erase (BraseroLibburn *self,
593 GError **error)
594 {
595 char reasons [BURN_REASONS_LEN];
596 struct burn_session *session;
597 struct burn_write_opts *opts;
598 BraseroLibburnPrivate *priv;
599 BraseroBurnResult result;
600 BraseroBurnFlag flags;
601 char prof_name [80];
602 int profile;
603 int fd;
604
605 priv = BRASERO_LIBBURN_PRIVATE (self);
606 if (burn_disc_get_profile (priv->ctx->drive, &profile, prof_name) <= 0) {
607 g_set_error (error,
608 BRASERO_BURN_ERROR,
609 BRASERO_BURN_ERROR_MEDIUM_INVALID,
610 _("The disc is not supported"));
611 return BRASERO_BURN_ERR;
612 }
613
614 /* here we try to respect the current formatting of DVD-RW. For
615 * overwritable media fast option means erase the first 64 Kib
616 * and long a forced reformatting */
617 brasero_job_get_flags (BRASERO_JOB (self), &flags);
618 if (profile == BRASERO_SCSI_PROF_DVD_RW_RESTRICTED) {
619 if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
620 /* leave libburn choose the best format */
621 if (!priv->sig_handler) {
622 burn_set_signal_handling ("brasero", NULL, 0);
623 priv->sig_handler = 1;
624 }
625
626 burn_disc_format (priv->ctx->drive,
627 (off_t) 0,
628 (1 << 4));
629 return BRASERO_BURN_OK;
630 }
631 }
632 else if (profile == BRASERO_SCSI_PROF_DVD_RW_PLUS) {
633 if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
634 /* Bit 2 is for format max available size
635 * Bit 4 is enforce (re)-format if needed
636 * 0x26 is DVD+RW format is to be set from bit 8
637 * in the latter case bit 7 needs to be set as
638 * well. */
639 if (!priv->sig_handler) {
640 burn_set_signal_handling ("brasero", NULL, 0);
641 priv->sig_handler = 1;
642 }
643
644 burn_disc_format (priv->ctx->drive,
645 (off_t) 0,
646 (1 << 2)|(1 << 4));
647 return BRASERO_BURN_OK;
648 }
649 }
650 else if (burn_disc_erasable (priv->ctx->drive)) {
651 /* This is mainly for CDRW and sequential DVD-RW */
652 if (!priv->sig_handler) {
653 burn_set_signal_handling ("brasero", NULL, 0);
654 priv->sig_handler = 1;
655 }
656
657 /* NOTE: for an unknown reason (to me)
658 * libburn when minimally blanking a DVD-RW
659 * will only allow to write to it with DAO
660 * afterwards... */
661 burn_disc_erase (priv->ctx->drive, (flags & BRASERO_BURN_FLAG_FAST_BLANK) != 0);
662 return BRASERO_BURN_OK;
663 }
664 else
665 BRASERO_JOB_NOT_SUPPORTED (self);
666
667 /* This is the "fast option": basically we only write 64 Kib of 0 from
668 * /dev/null. If we reached that part it means we're dealing with
669 * overwrite media. */
670 fd = open ("/dev/null", O_RDONLY);
671 if (fd == -1) {
672 int errnum = errno;
673
674 g_set_error (error,
675 BRASERO_BURN_ERROR,
676 BRASERO_BURN_ERROR_GENERAL,
677 /* Translators: first %s is the filename, second %s is the error
678 * generated from errno */
679 _("\"%s\" could not be opened (%s)"),
680 "/dev/null",
681 g_strerror (errnum));
682 return BRASERO_BURN_ERR;
683 }
684
685 priv->ctx->disc = burn_disc_create ();
686
687 /* create the session */
688 session = burn_session_create ();
689 burn_disc_add_session (priv->ctx->disc, session, BURN_POS_END);
690 burn_session_free (session);
691
692 result = brasero_libburn_add_fd_track (session,
693 fd,
694 BURN_MODE1,
695 65536, /* 32 blocks */
696 priv->pvd,
697 error);
698 close (fd);
699
700 opts = burn_write_opts_new (priv->ctx->drive);
701 burn_write_opts_set_perform_opc (opts, 0);
702 burn_write_opts_set_underrun_proof (opts, 1);
703 burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY));
704
705 burn_drive_set_speed (priv->ctx->drive, burn_drive_get_write_speed (priv->ctx->drive), 0);
706 burn_write_opts_set_write_type (opts,
707 BURN_WRITE_TAO,
708 BURN_BLOCK_MODE1);
709
710 if (burn_precheck_write (opts, priv->ctx->disc, reasons, 0) <= 0) {
711 burn_write_opts_free (opts);
712
713 g_set_error (error,
714 BRASERO_BURN_ERROR,
715 BRASERO_BURN_ERROR_GENERAL,
716 /* Translators: %s is the error returned by libburn */
717 _("An internal error occurred (%s)"),
718 reasons);
719 return BRASERO_BURN_ERR;
720 }
721
722 if (!priv->sig_handler) {
723 burn_set_signal_handling ("brasero", NULL, 0);
724 priv->sig_handler = 1;
725 }
726
727 burn_disc_write (opts, priv->ctx->disc);
728 burn_write_opts_free (opts);
729
730 return result;
731 }
732
733 static BraseroBurnResult
brasero_libburn_start(BraseroJob * job,GError ** error)734 brasero_libburn_start (BraseroJob *job,
735 GError **error)
736 {
737 BraseroLibburn *self;
738 BraseroJobAction action;
739 BraseroBurnResult result;
740 BraseroLibburnPrivate *priv;
741
742 self = BRASERO_LIBBURN (job);
743 priv = BRASERO_LIBBURN_PRIVATE (self);
744
745 brasero_job_get_action (job, &action);
746 if (action == BRASERO_JOB_ACTION_RECORD) {
747 GError *ret_error = NULL;
748
749 /* TRUE is a context that helps to adapt action
750 * messages like for DVD+RW which need a
751 * pre-formatting before actually writing
752 * and without this we would not know if
753 * we are actually formatting or just pre-
754 * formatting == starting to record */
755 priv->ctx = brasero_libburn_common_ctx_new (job, TRUE, &ret_error);
756 if (!priv->ctx) {
757 if (ret_error && ret_error->code == BRASERO_BURN_ERROR_DRIVE_BUSY) {
758 g_propagate_error (error, ret_error);
759 return BRASERO_BURN_RETRY;
760 }
761
762 if (error)
763 g_propagate_error (error, ret_error);
764 return BRASERO_BURN_ERR;
765 }
766
767 result = brasero_libburn_start_record (self, error);
768 if (result != BRASERO_BURN_OK)
769 return result;
770
771 brasero_job_set_current_action (job,
772 BRASERO_BURN_ACTION_START_RECORDING,
773 NULL,
774 FALSE);
775 }
776 else if (action == BRASERO_JOB_ACTION_ERASE) {
777 GError *ret_error = NULL;
778
779 priv->ctx = brasero_libburn_common_ctx_new (job, FALSE, &ret_error);
780 if (!priv->ctx) {
781 if (ret_error && ret_error->code == BRASERO_BURN_ERROR_DRIVE_BUSY) {
782 g_propagate_error (error, ret_error);
783 return BRASERO_BURN_RETRY;
784 }
785
786 if (error)
787 g_propagate_error (error, ret_error);
788 return BRASERO_BURN_ERR;
789 }
790
791 result = brasero_libburn_start_erase (self, error);
792 if (result != BRASERO_BURN_OK)
793 return result;
794
795 brasero_job_set_current_action (job,
796 BRASERO_BURN_ACTION_BLANKING,
797 NULL,
798 FALSE);
799 }
800 else
801 BRASERO_JOB_NOT_SUPPORTED (self);
802
803 return BRASERO_BURN_OK;
804 }
805
806 static BraseroBurnResult
brasero_libburn_stop(BraseroJob * job,GError ** error)807 brasero_libburn_stop (BraseroJob *job,
808 GError **error)
809 {
810 BraseroLibburn *self;
811 BraseroLibburnPrivate *priv;
812
813 self = BRASERO_LIBBURN (job);
814 priv = BRASERO_LIBBURN_PRIVATE (self);
815
816 if (priv->sig_handler) {
817 priv->sig_handler = 0;
818 burn_set_signal_handling (NULL, NULL, 1);
819 }
820
821 if (priv->ctx) {
822 brasero_libburn_common_ctx_free (priv->ctx);
823 priv->ctx = NULL;
824 }
825
826 if (priv->pvd) {
827 g_free (priv->pvd);
828 priv->pvd = NULL;
829 }
830
831 if (BRASERO_JOB_CLASS (parent_class)->stop)
832 BRASERO_JOB_CLASS (parent_class)->stop (job, error);
833
834 return BRASERO_BURN_OK;
835 }
836
837 static BraseroBurnResult
brasero_libburn_clock_tick(BraseroJob * job)838 brasero_libburn_clock_tick (BraseroJob *job)
839 {
840 BraseroLibburnPrivate *priv;
841 BraseroBurnResult result;
842 int ret;
843
844 priv = BRASERO_LIBBURN_PRIVATE (job);
845 result = brasero_libburn_common_status (job, priv->ctx);
846
847 if (result != BRASERO_BURN_OK)
848 return BRASERO_BURN_OK;
849
850 /* Double check that everything went well */
851 if (!burn_drive_wrote_well (priv->ctx->drive)) {
852 BRASERO_JOB_LOG (job, "Something went wrong");
853 brasero_job_error (job,
854 g_error_new (BRASERO_BURN_ERROR,
855 BRASERO_BURN_ERROR_WRITE_MEDIUM,
856 _("An error occurred while writing to disc")));
857 return BRASERO_BURN_OK;
858 }
859
860 /* That's finished */
861 if (!priv->pvd) {
862 brasero_job_set_dangerous (job, FALSE);
863 brasero_job_finished_session (job);
864 return BRASERO_BURN_OK;
865 }
866
867 /* In case we append data to a DVD+RW or DVD-RW
868 * (restricted overwrite) medium , we're not
869 * done since we need to overwrite the primary
870 * volume descriptor at sector 0.
871 * NOTE: This is a synchronous call but given the size of the buffer
872 * that shouldn't block.
873 * NOTE 2: in source we read the volume descriptors until we reached
874 * either the end of the buffer or the volume descriptor set end. That's
875 * kind of useless since for a DVD 16 blocks are written at a time. */
876 BRASERO_JOB_LOG (job, "Starting to overwrite primary volume descriptor");
877 ret = burn_random_access_write (priv->ctx->drive,
878 0,
879 (char*)priv->pvd,
880 BRASERO_PVD_SIZE,
881 0);
882 if (ret != 1) {
883 BRASERO_JOB_LOG (job, "Random write failed");
884 brasero_job_error (job,
885 g_error_new (BRASERO_BURN_ERROR,
886 BRASERO_BURN_ERROR_WRITE_MEDIUM,
887 _("An error occurred while writing to disc")));
888 return BRASERO_BURN_OK;
889 }
890
891 brasero_job_set_dangerous (job, FALSE);
892 brasero_job_finished_session (job);
893
894 return BRASERO_BURN_OK;
895 }
896
897 static void
brasero_libburn_class_init(BraseroLibburnClass * klass)898 brasero_libburn_class_init (BraseroLibburnClass *klass)
899 {
900 GObjectClass *object_class = G_OBJECT_CLASS (klass);
901 BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
902
903 g_type_class_add_private (klass, sizeof (BraseroLibburnPrivate));
904
905 parent_class = g_type_class_peek_parent(klass);
906 object_class->finalize = brasero_libburn_finalize;
907
908 job_class->start = brasero_libburn_start;
909 job_class->stop = brasero_libburn_stop;
910 job_class->clock_tick = brasero_libburn_clock_tick;
911 }
912
913 static void
brasero_libburn_init(BraseroLibburn * obj)914 brasero_libburn_init (BraseroLibburn *obj)
915 {
916
917 }
918
919 static void
brasero_libburn_finalize(GObject * object)920 brasero_libburn_finalize (GObject *object)
921 {
922 BraseroLibburn *cobj;
923 BraseroLibburnPrivate *priv;
924
925 cobj = BRASERO_LIBBURN (object);
926 priv = BRASERO_LIBBURN_PRIVATE (cobj);
927
928 if (priv->ctx) {
929 brasero_libburn_common_ctx_free (priv->ctx);
930 priv->ctx = NULL;
931 }
932
933 G_OBJECT_CLASS (parent_class)->finalize (object);
934 }
935
936 static void
brasero_libburn_export_caps(BraseroPlugin * plugin)937 brasero_libburn_export_caps (BraseroPlugin *plugin)
938 {
939 const BraseroMedia media_cd = BRASERO_MEDIUM_CD|
940 BRASERO_MEDIUM_REWRITABLE|
941 BRASERO_MEDIUM_WRITABLE|
942 BRASERO_MEDIUM_BLANK|
943 BRASERO_MEDIUM_APPENDABLE|
944 BRASERO_MEDIUM_HAS_AUDIO|
945 BRASERO_MEDIUM_HAS_DATA;
946 const BraseroMedia media_dvd_w = BRASERO_MEDIUM_DVD|
947 BRASERO_MEDIUM_PLUS|
948 BRASERO_MEDIUM_SEQUENTIAL|
949 BRASERO_MEDIUM_WRITABLE|
950 BRASERO_MEDIUM_APPENDABLE|
951 BRASERO_MEDIUM_HAS_DATA|
952 BRASERO_MEDIUM_BLANK;
953 const BraseroMedia media_dvd_rw = BRASERO_MEDIUM_DVD|
954 BRASERO_MEDIUM_SEQUENTIAL|
955 BRASERO_MEDIUM_REWRITABLE|
956 BRASERO_MEDIUM_APPENDABLE|
957 BRASERO_MEDIUM_HAS_DATA|
958 BRASERO_MEDIUM_BLANK;
959 const BraseroMedia media_dvd_rw_plus = BRASERO_MEDIUM_DVD|
960 BRASERO_MEDIUM_DUAL_L|
961 BRASERO_MEDIUM_PLUS|
962 BRASERO_MEDIUM_RESTRICTED|
963 BRASERO_MEDIUM_REWRITABLE|
964 BRASERO_MEDIUM_UNFORMATTED|
965 BRASERO_MEDIUM_BLANK|
966 BRASERO_MEDIUM_APPENDABLE|
967 BRASERO_MEDIUM_CLOSED|
968 BRASERO_MEDIUM_HAS_DATA;
969 GSList *output;
970 GSList *input;
971
972 brasero_plugin_define (plugin,
973 "libburn",
974 NULL,
975 _("Burns, blanks and formats CDs, DVDs and BDs"),
976 "Philippe Rouquier",
977 15);
978
979 /* libburn has no OVERBURN capabilities */
980
981 /* CD(R)W */
982 /* Use DAO for first session since AUDIO need it to write CD-TEXT
983 * Though libburn is unable to write CD-TEXT.... */
984 /* Note: when burning multiple tracks to a CD (like audio for example)
985 * in dummy mode with TAO libburn will fail probably because it does
986 * not use a correct next writable address for the second track (it uses
987 * the same as for track #1). So remove dummy mode.
988 * This is probably the same reason why it fails at merging another
989 * session to a data CD in dummy mode. */
990 BRASERO_PLUGIN_ADD_STANDARD_CDR_FLAGS (plugin,
991 BRASERO_BURN_FLAG_OVERBURN|
992 BRASERO_BURN_FLAG_DUMMY);
993 BRASERO_PLUGIN_ADD_STANDARD_CDRW_FLAGS (plugin,
994 BRASERO_BURN_FLAG_OVERBURN|
995 BRASERO_BURN_FLAG_DUMMY);
996
997 /* audio support for CDs only */
998 input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
999 BRASERO_PLUGIN_IO_ACCEPT_FILE,
1000 BRASERO_AUDIO_FORMAT_RAW_LITTLE_ENDIAN);
1001
1002 output = brasero_caps_disc_new (media_cd);
1003 brasero_plugin_link_caps (plugin, output, input);
1004 g_slist_free (input);
1005
1006 /* Image support for CDs ... */
1007 input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
1008 BRASERO_PLUGIN_IO_ACCEPT_FILE,
1009 BRASERO_IMAGE_FORMAT_BIN);
1010
1011 brasero_plugin_link_caps (plugin, output, input);
1012 g_slist_free (output);
1013
1014 /* ... and DVD-R and DVD+R ... */
1015 output = brasero_caps_disc_new (media_dvd_w);
1016 brasero_plugin_link_caps (plugin, output, input);
1017 g_slist_free (output);
1018
1019 BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
1020 BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
1021
1022 /* ... and DVD-RW (sequential) */
1023 output = brasero_caps_disc_new (media_dvd_rw);
1024 brasero_plugin_link_caps (plugin, output, input);
1025 g_slist_free (output);
1026
1027 BRASERO_PLUGIN_ADD_STANDARD_DVDRW_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
1028
1029 /* for DVD+/-RW restricted */
1030 output = brasero_caps_disc_new (media_dvd_rw_plus);
1031 brasero_plugin_link_caps (plugin, output, input);
1032 g_slist_free (output);
1033 g_slist_free (input);
1034
1035 BRASERO_PLUGIN_ADD_STANDARD_DVDRW_RESTRICTED_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
1036 BRASERO_PLUGIN_ADD_STANDARD_DVDRW_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
1037
1038 /* add blank caps */
1039 output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
1040 BRASERO_MEDIUM_REWRITABLE|
1041 BRASERO_MEDIUM_APPENDABLE|
1042 BRASERO_MEDIUM_CLOSED|
1043 BRASERO_MEDIUM_HAS_DATA|
1044 BRASERO_MEDIUM_HAS_AUDIO|
1045 BRASERO_MEDIUM_BLANK);
1046 brasero_plugin_blank_caps (plugin, output);
1047 g_slist_free (output);
1048
1049 output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
1050 BRASERO_MEDIUM_PLUS|
1051 BRASERO_MEDIUM_SEQUENTIAL|
1052 BRASERO_MEDIUM_RESTRICTED|
1053 BRASERO_MEDIUM_REWRITABLE|
1054 BRASERO_MEDIUM_APPENDABLE|
1055 BRASERO_MEDIUM_CLOSED|
1056 BRASERO_MEDIUM_HAS_DATA|
1057 BRASERO_MEDIUM_UNFORMATTED|
1058 BRASERO_MEDIUM_BLANK);
1059 brasero_plugin_blank_caps (plugin, output);
1060 g_slist_free (output);
1061
1062 brasero_plugin_set_blank_flags (plugin,
1063 BRASERO_MEDIUM_CD|
1064 BRASERO_MEDIUM_DVD|
1065 BRASERO_MEDIUM_SEQUENTIAL|
1066 BRASERO_MEDIUM_RESTRICTED|
1067 BRASERO_MEDIUM_REWRITABLE|
1068 BRASERO_MEDIUM_APPENDABLE|
1069 BRASERO_MEDIUM_CLOSED|
1070 BRASERO_MEDIUM_HAS_DATA|
1071 BRASERO_MEDIUM_HAS_AUDIO|
1072 BRASERO_MEDIUM_UNFORMATTED|
1073 BRASERO_MEDIUM_BLANK,
1074 BRASERO_BURN_FLAG_NOGRACE|
1075 BRASERO_BURN_FLAG_FAST_BLANK,
1076 BRASERO_BURN_FLAG_NONE);
1077
1078 /* no dummy mode for DVD+RW */
1079 brasero_plugin_set_blank_flags (plugin,
1080 BRASERO_MEDIUM_DVDRW_PLUS|
1081 BRASERO_MEDIUM_APPENDABLE|
1082 BRASERO_MEDIUM_CLOSED|
1083 BRASERO_MEDIUM_HAS_DATA|
1084 BRASERO_MEDIUM_UNFORMATTED|
1085 BRASERO_MEDIUM_BLANK,
1086 BRASERO_BURN_FLAG_NOGRACE|
1087 BRASERO_BURN_FLAG_FAST_BLANK,
1088 BRASERO_BURN_FLAG_NONE);
1089
1090 brasero_plugin_register_group (plugin, _(LIBBURNIA_DESCRIPTION));
1091 }
1092