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