1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
2 
3 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
4    Copyright (c) 2006 - 2017 Thomas Schmitt <scdbackup@gmx.net>
5    Provided under GPL version 2 or later.
6 */
7 
8 
9 #ifdef HAVE_CONFIG_H
10 #include "../config.h"
11 #endif
12 
13 #include <unistd.h>
14 #include <signal.h>
15 
16 /* ts A61009 */
17 /* #include <a ssert.h> */
18 
19 
20 /* ts A61106 : Deliberate defect provocation macros
21                DO NOT DEFINE THESE IF YOU WANT SUCCESSFUL TAO !
22 #define Libburn_experimental_no_close_tracK 1
23 #define Libburn_experimental_no_close_sessioN 1
24 */
25 
26 /* ts A61114 : Highly experimental : try to achieve SAO on appendables
27                THIS DOES NOT WORK YET !
28 #define Libburn_sao_can_appenD 1
29 */
30 
31 #include <sys/types.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 
41 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
45 
46 #include "error.h"
47 #include "sector.h"
48 #include "libburn.h"
49 #include "drive.h"
50 #include "transport.h"
51 #include "debug.h"
52 #include "init.h"
53 #include "toc.h"
54 #include "util.h"
55 #include "sg.h"
56 #include "write.h"
57 #include "options.h"
58 #include "structure.h"
59 #include "source.h"
60 #include "mmc.h"
61 #include "spc.h"
62 
63 #include "libdax_msgs.h"
64 extern struct libdax_msgs *libdax_messenger;
65 
66 
67 /* ts A91120 : <<< experimental */
68 #ifdef Libburn_mmap_write_buffeR
69 #include <sys/mman.h>
70 #endif
71 
72 
73 /* The maximum output size to be used with CD media. This is also curbed
74    by BURN_OS_TRANSPORT_BUFFER_SIZE. The smaller number gets into effect.
75 */
76 #define Libburn_cd_obS (32 * 1024)
77 
78 /* The size to be used with DVD media.
79 */
80 #define Libburn_dvd_obS (32 * 1024)
81 
82 /* The size to be used with BD-RE media in normal, not streamed mode.
83 */
84 #define Libburn_bd_re_obS (64 * 1024)
85 
86 /* The size to be used with BD-R media in normal, not streamed mode.
87 */
88 #define Libburn_bd_r_obS (64 * 1024)
89 
90 /* The size to be used with BD-RE and BD-R media in streamed mode.
91 */
92 #define Libburn_bd_streamed_obS (64 * 1024)
93 
94 /* The number of retries if write(2) returns a short, non-negative write count.
95 */
96 #define Libburn_stdio_write_retrieS 16
97 
98 
type_to_ctrl(int mode)99 static int type_to_ctrl(int mode)
100 {
101 	int ctrl = 0;
102 
103 	int data = BURN_MODE2 | BURN_MODE1 | BURN_MODE0;
104 
105 	if (mode & data) {
106 		ctrl |= 4;
107 	} else if (mode & BURN_AUDIO) {
108 		if (mode & BURN_4CH)
109 			ctrl |= 8;
110 		if (mode & BURN_PREEMPHASIS)
111 			ctrl |= 1;
112 	} else
113 		/* ts A61008 */
114 		/* a ssert(0); */
115 		return -1;
116 
117 	if (mode & BURN_COPY)
118 		ctrl |= 2;
119 
120 	return ctrl;
121 }
122 
123 /* only the ctrl nibble is set here (not adr) */
124 /* ts A61009 : removed "static" , reacted on type_to_ctrl() == -1
125                preserved ignorance towards unknown modes (for now) */
type_to_form(int mode,unsigned char * ctladr,int * form)126 void type_to_form(int mode, unsigned char *ctladr, int *form)
127 {
128 	int ret;
129 
130 	ret = type_to_ctrl(mode) << 4;
131 	if (ret == -1) {
132 		*ctladr = 0xff;
133 		*form = -1;
134 		return;
135 	}
136 	*ctladr = ret;
137 
138 	if (mode & BURN_AUDIO)
139 		*form = 0;
140 	if (mode & BURN_MODE0) {
141 
142 		/* ts A61009 */
143 		/* a ssert(0); */
144 		*form = -1;
145 		return;
146 	}
147 
148 	if (mode & BURN_MODE1)
149 		*form = 0x10;
150 	if (mode & BURN_MODE2) {
151 
152 		/* ts A61009 */
153 		/* a ssert(0); */ /* XXX someone's gonna want this sometime */
154 		*form = -1;
155 		return;
156 	}
157 
158 	if (mode & BURN_MODE_RAW)
159 		*form = 0;
160 	if (mode & BURN_SUBCODE_P16)	/* must be expanded to R96 */
161 		*form |= 0x40;
162 	if (mode & BURN_SUBCODE_P96)
163 		*form |= 0xC0;
164 	if (mode & BURN_SUBCODE_R96)
165 		*form |= 0x40;
166 }
167 
168 
169 /* ts A71002 : outsourced from burn_write_flush() : no sync cache here */
burn_write_flush_buffer(struct burn_write_opts * o,struct burn_track * track)170 int burn_write_flush_buffer(struct burn_write_opts *o,struct burn_track *track)
171 {
172 	struct burn_drive *d = o->drive;
173 
174 	if (d->buffer->bytes && !d->cancel) {
175 		int err;
176 		err = d->write(d, d->nwa, d->buffer);
177 		if (err == BE_CANCELLED)
178 			return 0;
179 		/* A61101 */
180 		if(track != NULL) {
181 			track->writecount += d->buffer->bytes;
182 			track->written_sectors += d->buffer->sectors;
183 		}
184 		/* ts A61119 */
185 		d->progress.buffered_bytes += d->buffer->bytes;
186 
187 		d->nwa += d->buffer->sectors;
188 		d->buffer->bytes = 0;
189 		d->buffer->sectors = 0;
190 	}
191 	return 1;
192 }
193 
194 
burn_write_flush(struct burn_write_opts * o,struct burn_track * track)195 int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
196 {
197 	int ret;
198 	struct burn_drive *d = o->drive;
199 
200 	ret = burn_write_flush_buffer(o, track);
201 	if (ret <= 0)
202 		return ret;
203 	d->sync_cache(d);
204 	return 1;
205 }
206 
207 
208 /* ts A71002 : outsourced from burn_write_close_track() */
burn_write_track_minsize(struct burn_write_opts * o,struct burn_session * s,int tnum)209 int burn_write_track_minsize(struct burn_write_opts *o, struct burn_session *s,
210 				int tnum)
211 {
212 	char msg[81];
213 	struct burn_drive *d;
214 	struct burn_track *t;
215 	int todo, step, cancelled, seclen;
216 
217 	d = o->drive;
218 	t = s->track[tnum];
219 
220 	/* ts A61103 : pad up track to minimum size of 600 sectors */
221 	if (t->written_sectors < 300) {
222 		todo = 300 - t->written_sectors;
223 		sprintf(msg,"Padding up track to minimum size (+ %d sectors)",
224 			todo);
225 		libdax_msgs_submit(libdax_messenger, o->drive->global_index,
226 			0x0002011a,
227 			LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
228 		step = BUFFER_SIZE / 4096; /* shall fit any sector size */
229 		seclen = burn_sector_length(t->mode);
230 		if (seclen <= 0)
231 			seclen = 2048;
232 		memset(d->buffer, 0, sizeof(struct buffer));
233 		cancelled = d->cancel;
234 		for (; todo > 0; todo -= step) {
235 			if (step > todo)
236 				step = todo;
237 			d->buffer->bytes = step*seclen;
238 			d->buffer->sectors = step;
239 			d->cancel = 0;
240 			d->write(d, d->nwa, d->buffer);
241 			d->nwa += d->buffer->sectors;
242 			t->writecount += d->buffer->bytes;
243 			t->written_sectors += d->buffer->sectors;
244 			d->progress.buffered_bytes += d->buffer->bytes;
245 		}
246 		d->cancel = cancelled;
247 	}
248 	return 1;
249 }
250 
251 
252 /* ts A61030 */
burn_write_close_track(struct burn_write_opts * o,struct burn_session * s,int tnum)253 int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
254 				int tnum)
255 {
256 	char msg[81];
257 	struct burn_drive *d;
258 
259 	/* ts A61106 */
260 #ifdef Libburn_experimental_no_close_tracK
261 	return 1;
262 #endif
263 
264 	d = o->drive;
265 
266 	d->busy = BURN_DRIVE_CLOSING_TRACK;
267 
268 	sprintf(msg, "Closing track %2.2d", tnum+1);
269 	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
270 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
271 
272 	/* MMC-1 mentions track number 0xFF for "the incomplete track",
273 	   MMC-3 does not. I tried both. 0xFF was in effect when other
274 	   bugs finally gave up and made way for readable tracks. */
275 	/* ts A70129
276 	   Probably the right value for appendables is d->last_track_no
277 	*/
278 	d->close_track_session(o->drive, 0, 0xff);
279 
280 	d->busy = BURN_DRIVE_WRITING;
281 
282 	return 1;
283 }
284 
285 
286 /* ts A61030 */
burn_write_close_session(struct burn_write_opts * o)287 int burn_write_close_session(struct burn_write_opts *o)
288 {
289 
290 	/* ts A61106 */
291 #ifdef Libburn_experimental_no_close_sessioN
292 	return 1;
293 #endif
294 
295 	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
296 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
297 			"Closing session", 0, 0);
298 
299 	/* ts A61102 */
300 	o->drive->busy = BURN_DRIVE_CLOSING_SESSION;
301 
302 	o->drive->close_track_session(o->drive, 1, 0);
303 
304 	/* ts A61102 */
305 	o->drive->busy = BURN_DRIVE_WRITING;
306 
307 	return 1;
308 }
309 
310 
311 /* ts A60819, B20101:
312    This is useful only when changes about CD SAO get tested.
313  # define Libburn_write_with_function_print_cuE yes
314 */
315 
316 #ifdef Libburn_write_with_function_print_cuE
317 
318 
cue_printify(char c)319 static char cue_printify(char c)
320 {
321 	if (c >= 32 && c < 127)
322 		return c;
323 	return '#';
324 }
325 
326 
print_cue(struct cue_sheet * sheet)327 static void print_cue(struct cue_sheet *sheet)
328 {
329 	int i;
330 	unsigned char *unit;
331 
332 	printf("\n");
333 	printf("ctladr|trno|indx|form|scms|   msf    |  text\n");
334 	printf("------+----+----+----+----+----------+--------\n");
335 	for (i = 0; i < sheet->count; i++) {
336 		unit = sheet->data + 8 * i;
337 		if ((unit[0] & 0xf) == 2) {
338 			printf(
339 		" %1X  %1X |    |    |    |    |          | %c%c%c%c%c%c%c\n",
340 				(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
341 				cue_printify(unit[1]), cue_printify(unit[2]),
342 				cue_printify(unit[3]), cue_printify(unit[4]),
343 				cue_printify(unit[5]), cue_printify(unit[6]),
344 				unit[7] == 0 ? ' ' : cue_printify(unit[7]));
345 		} else if ((unit[0] & 0xf) == 3) {
346 			printf(
347 		" %1X  %1X | %2d |    |    |    |          | %c%c%c%c%c%c\n",
348 				(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
349 				unit[1], cue_printify(unit[2]),
350 				cue_printify(unit[3]), cue_printify(unit[4]),
351 				cue_printify(unit[5]), cue_printify(unit[6]),
352 				cue_printify(unit[7]));
353 		} else if (unit[1] > 99) {
354 			printf(" %1X  %1X |0x%02X| %2d | %02X | %02X |",
355 				(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
356 				unit[1], unit[2], unit[3], unit[4]);
357 			printf(" %02d:%02d:%02d |\n",
358 				unit[5], unit[6], unit[7]);
359 		} else {
360 			printf(" %1X  %1X | %2d | %2d | %02X | %02X |",
361 				(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
362 				unit[1], unit[2], unit[3], unit[4]);
363 			printf(" %02d:%02d:%02d |\n",
364 				unit[5], unit[6], unit[7]);
365 		}
366 	}
367 	fflush(stdout);
368 }
369 
370 #endif /* Libburn_write_with_print_cuE */
371 
372 
373 /* ts B11226 */
new_cue(struct cue_sheet * sheet,int number,int flag)374 static int new_cue(struct cue_sheet *sheet, int number, int flag)
375 {
376 	unsigned char *ptr;
377 
378 	ptr = realloc(sheet->data, (sheet->count + number) * 8);
379 	if (ptr == NULL) {
380 		libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
381 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
382 		"Could not allocate new auxiliary object (cue_sheet->data)",
383 			0, 0);
384 		return -1;
385 	}
386 	sheet->data = ptr;
387 	sheet->count += number;
388 	return 1;
389 }
390 
391 
392 /* ts B11226 : outsourced new_cue() */
393 /** @return 1 = success , <=0 failure */
add_cue(struct cue_sheet * sheet,unsigned char ctladr,unsigned char tno,unsigned char indx,unsigned char form,unsigned char scms,int lba)394 static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
395 		    unsigned char tno, unsigned char indx,
396 		    unsigned char form, unsigned char scms, int lba)
397 {
398 	unsigned char *unit;
399 	int m, s, f, ret;
400 
401 	burn_lba_to_msf(lba, &m, &s, &f);
402 
403 	ret = new_cue(sheet, 1, 0);
404 	if (ret <= 0)
405 		return -1;
406 	unit = sheet->data + (sheet->count - 1) * 8;
407 	unit[0] = ctladr;
408 	unit[1] = tno;
409 	unit[2] = indx;
410 	unit[3] = form;
411 	unit[4] = scms;
412 	unit[5] = m;
413 	unit[6] = s;
414 	unit[7] = f;
415 	return 1;
416 }
417 
418 
419 /* ts B11226 */
add_catalog_cue(struct cue_sheet * sheet,unsigned char catalog[13])420 static int add_catalog_cue(struct cue_sheet *sheet, unsigned char catalog[13])
421 {
422 	unsigned char *unit;
423 	int i, ret;
424 
425 	ret = new_cue(sheet, 2, 0);
426 	if (ret <= 0)
427 		return -1;
428 	unit = sheet->data + (sheet->count - 2) * 8;
429 	unit[0] = unit[8] = 0x02;
430 	for (i = 0; i < 13; i++)
431 		unit[1 + (i >= 7) * 8 + (i % 7)] = catalog[i];
432 	unit[15] = 0x00;
433 	return 1;
434 }
435 
436 
437 /* ts B11226 */
add_isrc_cue(struct cue_sheet * sheet,unsigned char ctladr,int tno,struct isrc * isrc)438 static int add_isrc_cue(struct cue_sheet *sheet, unsigned char ctladr, int tno,
439 			struct isrc *isrc)
440 {
441 	unsigned char *unit;
442 	int i, ret;
443 	char text[8 + 21]; /* should suffice for 64 bit oversize */
444 
445 	ret = new_cue(sheet, 2, 0);
446 	if (ret <= 0)
447 		return -1;
448 	unit = sheet->data + (sheet->count - 2) * 8;
449 	unit[0] = unit[8] = (ctladr & 0xf0) | 0x03;
450 	unit[1] = unit[9] = tno;
451 	unit[2] = isrc->country[0];
452 	unit[3] = isrc->country[1];
453 	unit[4] = isrc->owner[0];
454 	unit[5] = isrc->owner[1];
455 	unit[6] = isrc->owner[2];
456 	sprintf(text, "%-2.2u%-5.5u", (unsigned int) isrc->year, isrc->serial);
457 	sprintf(text, "%-2.2u", (unsigned int) isrc->year);
458 	sprintf(text + 2, "%-5.5u", isrc->serial);
459 	text[7] = 0;
460 	unit[7] = text[0];
461 	for (i = 1; i < 7; i++)
462 		unit[9 + i] = text[i];
463 	return 1;
464 }
465 
466 
467 /* ts A61114: added parameter nwa */
burn_create_toc_entries(struct burn_write_opts * o,struct burn_session * session,int nwa)468 struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
469 					  struct burn_session *session,
470 					  int nwa)
471 {
472 	int i, m, s, f, form, runtime = -150, ret, track_length;
473 	int leadin_form, leadin_start, pregap = 150, postgap;
474 	unsigned char ctladr, scms;
475 	struct burn_drive *d;
476 	struct burn_toc_entry *e;
477 	struct cue_sheet *sheet;
478 	struct burn_track **tar = session->track;
479 	int ntr = session->tracks;
480 	int rem = 0;
481 
482 #define Libburn_track_multi_indeX yes
483 
484 #ifdef Libburn_track_multi_indeX
485 	int j;
486 #else
487 	int pform;
488 #endif
489 
490 	if (ntr < 1) {
491 		libdax_msgs_submit(libdax_messenger, -1, 0x0002019c,
492 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
493 			"Session has no defined tracks", 0, 0);
494 		return NULL;
495 	}
496 
497 	d = o->drive;
498 
499 #ifdef Libburn_sao_can_appenD
500 	if (d->status == BURN_DISC_APPENDABLE)
501  		runtime = nwa-150;
502 #endif
503 
504 	sheet = calloc(1, sizeof(struct cue_sheet));
505 
506 	/* ts A61009 : react on failures of calloc(), add_cue_sheet()
507 	               type_to_form() */
508 	if (sheet == NULL) {
509 		libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
510 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
511 			"Could not allocate new auxiliary object (cue_sheet)",
512 			0, 0);
513 		return NULL;
514 	}
515 
516 	sheet->data = NULL;
517 	sheet->count = 0;
518 	type_to_form(tar[0]->mode, &ctladr, &form);
519 	if (form == -1) {
520 		libdax_msgs_submit(libdax_messenger, -1, 0x00020116,
521 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
522 			"Track mode has unusable value", 0, 0);
523 		goto failed;
524 	}
525 	if (tar[0]->mode & BURN_AUDIO)
526 		leadin_form = 0x01;
527 	else
528 		leadin_form = 0x14;
529 	if (o->num_text_packs > 0) {
530 		leadin_form |= 0x40;
531 	} else {
532 		/* Check for CD-TEXT in session. Not the final creation,
533 		   because the cue sheet content might be needed for CD-TEXT
534 		   pack type 0x88 "TOC".
535 		 */
536 		if (o->text_packs == NULL) {
537 			ret = burn_cdtext_from_session(session, NULL, NULL, 1);
538 			if (ret < 0)
539 				goto failed;
540 			else if (ret > 0)
541 				leadin_form |= 0x40;
542 		}
543 	}
544 
545 	if (o->has_mediacatalog)
546 		ret = add_catalog_cue(sheet, o->mediacatalog);
547 	else if (session->mediacatalog[0])
548 		ret = add_catalog_cue(sheet, session->mediacatalog);
549 	else
550 		ret = 1;
551 	if (ret <= 0)
552 		goto failed;
553 
554 	/* ts B11225
555 	   MMC-5 6.33.3.15 Data Form of Sub-channel
556 	   seems to indicate that for leadin_form 0x41 one should announce
557 	   d->start_lba as start of the leadin (e.g. -12490) and that data
558 	   block type should 2 or 3 with mode page 05h. But my drives refuse
559 	   on that.
560            It works with LBA -150 and data block type 0. Shrug.
561 	*/
562 	leadin_start = runtime;
563 	ret = add_cue(sheet, (ctladr & 64) | 1, 0, 0, leadin_form, 0,
564 								leadin_start);
565 	if (ret <= 0)
566 		goto failed;
567 
568 	d->toc_entries = ntr + 3;
569 
570 	/* ts A61009 */
571 	/* a ssert(d->toc_entry == NULL); */
572 	if (d->toc_entry != NULL) {
573 
574 		/* ts A61109 : this happens with appendable CDs
575 			>>> Open question: is the existing TOC needed ? */
576 
577 		/* ts A61109 : for non-SAO, this sheet is thrown away later */
578 		free((char *) d->toc_entry);
579 
580 		/*
581 		libdax_msgs_submit(libdax_messenger,
582 			d->global_index, 0x00020117,
583 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
584 			"toc_entry of drive is already in use", 0, 0);
585 		goto failed;
586 		*/
587 	}
588 	if (session->firsttrack + ntr - 1 > 99) {
589 		libdax_msgs_submit(libdax_messenger, -1, 0x0002019b,
590 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
591 			"CD track number exceeds 99", 0, 0);
592 		goto failed;
593 	}
594 	session->lasttrack = session->firsttrack + ntr - 1;
595 
596 	d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
597 	e = d->toc_entry;
598 	e[0].point = 0xA0;
599 	if (tar[0]->mode & BURN_AUDIO)
600 		e[0].control = TOC_CONTROL_AUDIO;
601 	else
602 		e[0].control = TOC_CONTROL_DATA;
603 	e[0].pmin = session->firsttrack;
604 	e[0].psec = o->format;
605 	e[0].adr = 1;
606 	e[1].point = 0xA1;
607 	e[1].pmin = session->lasttrack;
608 	e[1].adr = 1;
609 	if (tar[ntr - 1]->mode & BURN_AUDIO)
610 		e[1].control = TOC_CONTROL_AUDIO;
611 	else
612 		e[1].control = TOC_CONTROL_DATA;
613 	e[2].point = 0xA2;
614 	e[2].control = e[1].control;
615 	e[2].adr = 1;
616 
617 	tar[0]->pregap2 = 1;
618 	if (tar[0]->pregap2_size < 150)
619 		tar[0]->pregap2_size = 150;
620 
621 #ifndef Libburn_track_multi_indeX
622 	pform = form;
623 #endif
624 
625 	for (i = 0; i < ntr; i++) {
626 
627 		/* ts A70125 :
628 		   Still not understanding the sense behind linking tracks,
629 		   i decided to at least enforce the MMC specs' minimum
630 		   track length.
631 		*/
632 		track_length = burn_track_get_sectors_2(tar[i], 1);
633 		if (track_length < 300 && !burn_track_is_open_ended(tar[i])) {
634 			track_length = 300;
635 			if (!tar[i]->pad)
636 				tar[i]->pad = 1;
637 			burn_track_set_sectors(tar[i], track_length);
638 		}
639 
640 		type_to_form(tar[i]->mode, &ctladr, &form);
641 		if (tar[i]->mode & BURN_SCMS)
642 			scms = 0x80;
643 		else
644 			scms = 0;
645 
646 		if (tar[i]->isrc.has_isrc) {
647 			ret = add_isrc_cue(sheet, ctladr,
648 				i + session->firsttrack, &(tar[i]->isrc));
649 			if (ret <= 0)
650 				goto failed;
651 		}
652 		pregap = 0;
653 		if (tar[i]->pregap2)
654 			pregap = tar[i]->pregap2_size;
655 		postgap = 0;
656 		if (tar[i]->postgap) {
657 			if (tar[i]->indices >= 99) {
658 				libdax_msgs_submit(libdax_messenger, -1,
659 					0x0002019a, LIBDAX_MSGS_SEV_SORRY,
660 					LIBDAX_MSGS_PRIO_HIGH,
661 					"Post-gap index number exceeds 99",
662 					0, 0);
663 				goto failed;
664 			}
665 			if (tar[i]->indices < 2)
666 				tar[i]->indices = 2;
667 			tar[i]->index[tar[i]->indices] = track_length;
668 			postgap = tar[i]->postgap_size;
669 		}
670 
671 #ifdef Libburn_track_multi_indeX
672 
673 		for(j = 0; j < (tar[i]->indices + !!tar[i]->postgap) || j < 2;
674 									j++) {
675 			if(tar[i]->index[j] == 0x7fffffff) {
676 				if (j > 1)
677 		break;
678 				if (j == 0 && pregap <= 0)
679 		continue;
680 				/* force existence of mandatory index */
681 				tar[i]->index[j] = 0;
682 			} else if (j == 0) {
683 				tar[i]->index[j] = 0;
684 			} else if (j == 1 && tar[i]->index[0] == 0x7fffffff) {
685 				tar[i]->index[j] = 0;
686 			}
687 
688 			if (j == 1) {
689 				tar[i]->entry = &e[3 + i];
690 				e[3 + i].point = i + session->firsttrack;
691 				burn_lba_to_msf(runtime, &m, &s, &f);
692 				e[3 + i].pmin = m;
693 				e[3 + i].psec = s;
694 				e[3 + i].pframe = f;
695 				e[3 + i].adr = 1;
696 				e[3 + i].control = type_to_ctrl(tar[i]->mode);
697 			}
698 
699 			/* >>> ??? else if j == 0 && mode change to -data :
700 							Extended pregap */;
701 
702 			/* >>> check index with track size */;
703 
704 			tar[i]->index[j] += runtime;
705 			ret = add_cue(sheet, ctladr | 1,
706 					i + session->firsttrack, j, form, scms,
707 					tar[i]->index[j]);
708 			if (ret <= 0)
709 				goto failed;
710 			runtime += pregap;
711 			pregap = 0;
712 		}
713 
714 		runtime += track_length + postgap;
715 
716 #else /* Libburn_track_multi_indeX */
717 
718 		if (i == 0) {
719 			ret = add_cue(sheet, ctladr | 1, session->firsttrack,
720 					0, form, 0, runtime);
721 			if (ret <= 0)
722 				goto failed;
723 			runtime += 150;
724 		} else if (pform != form) {
725 
726 		/* ts A70121 : This seems to be the wrong test. Correct would
727 		   be to compare tar[]->mode or bit2 of ctladr.
728 		*/
729 
730 			ret = add_cue(sheet, ctladr | 1,
731 					i + session->firsttrack, 0, form, scms,
732 					runtime);
733 			if (ret <= 0)
734 				goto failed;
735 
736 			runtime += 150;
737 /* XXX fix pregap interval 1 for data tracks */
738 /* ts A60813 silence righteous compiler warning about C++ style comments
739    This is possibly not a comment but rather a trace of Derek Foreman
740    experiments. Thus not to be beautified - but to be preserved rectified.
741 / /                      if (!(form & BURN_AUDIO))
742 / /                              tar[i]->pregap1 = 1;
743 */
744 /* ts A70121 : it is unclear why (form & BURN_AUDIO) should prevent pregap1.
745    I believe, correct would be:
746 			runtime += 75;
747 			tar[i]->pregap1 = 1;
748 
749    The test for pform != form is wrong anyway.
750 
751    Next one has to care for Post-gap: table 555 in mmc5r03c.pdf does not
752    show any although 6.33.3.19 would prescribe some.
753    ts B20111: Table 1 of MMC-1 shows two post-gaps. The first matches the
754               precriptions with SEND CUE SHEET. The second one is riddling.
755               Both are part of a track and occupy the range of the last index
756               of the track. Length is 2 seconds for each.
757 
758    Nobody seems to have ever tested this situation, up to now.
759    It is banned for now in burn_disc_write().
760    Warning have been placed in libburn.h .
761 */
762 
763 			tar[i]->pregap2 = 1;
764 		}
765 /* XXX HERE IS WHERE WE DO INDICES IN THE CUE SHEET */
766 /* XXX and we should make sure the gaps conform to ecma-130... */
767 		tar[i]->entry = &e[3 + i];
768 		e[3 + i].point = i + session->firsttrack;
769 		burn_lba_to_msf(runtime, &m, &s, &f);
770 		e[3 + i].pmin = m;
771 		e[3 + i].psec = s;
772 		e[3 + i].pframe = f;
773 		e[3 + i].adr = 1;
774 		e[3 + i].control = type_to_ctrl(tar[i]->mode);
775 
776 		ret = add_cue(sheet, ctladr | 1, i + session->firsttrack,
777 				1, form, scms, runtime);
778 		if (ret <= 0)
779 			goto failed;
780 
781 		runtime += track_length;
782 
783 #endif /* ! Libburn_track_multi_indeX */
784 
785 
786 /* if we're padding, we'll clear any current shortage.
787    if we're not, we'll slip toc entries by a sector every time our
788    shortage is more than a sector
789 XXX this is untested :)
790 */
791 		if (!tar[i]->pad) {
792 			rem += burn_track_get_shortage(tar[i]);
793 
794 			/* ts A61101 : I doubt that linking would yield a
795 					desirable effect. With TAO it is
796 					counterproductive in any way.
797 			*/
798 			if (o->write_type == BURN_WRITE_TAO)
799 				tar[i]->source->next = NULL;
800 			else
801 
802 				if (i +1 != ntr)
803 					tar[i]->source->next = tar[i+1]->source;
804 		} else if (rem) {
805 			rem = 0;
806 			runtime++;
807 		}
808 		if (rem > burn_sector_length(tar[i]->mode)) {
809 			rem -= burn_sector_length(tar[i]->mode);
810 			runtime--;
811 		}
812 
813 #ifndef Libburn_track_multi_indeX
814 		pform = form;
815 #endif
816 
817 	}
818 	burn_lba_to_msf(runtime, &m, &s, &f);
819 	e[2].pmin = m;
820 	e[2].psec = s;
821 	e[2].pframe = f;
822 
823 	ret = add_cue(sheet, ctladr | 1, 0xAA, 1, leadin_form & 0x3f,
824                       0, runtime);
825 	if (ret <= 0)
826 		goto failed;
827 	return sheet;
828 
829 failed:;
830 	if (sheet != NULL)
831 		free((char *) sheet);
832 	return NULL;
833 }
834 
burn_sector_length(int tracktype)835 int burn_sector_length(int tracktype)
836 {
837 	if (tracktype & BURN_AUDIO)
838 		return 2352;
839 	if (tracktype & BURN_MODE_RAW)
840 		return 2352;
841 	if (tracktype & BURN_MODE1)
842 		return 2048;
843 	/* ts A61009 */
844 	/* a ssert(0); */
845 	return -1;
846 }
847 
burn_subcode_length(int tracktype)848 int burn_subcode_length(int tracktype)
849 {
850 	if (tracktype & BURN_SUBCODE_P16)
851 		return 16;
852 	if ((tracktype & BURN_SUBCODE_P96) || (tracktype & BURN_SUBCODE_R96))
853 		return 96;
854 	return 0;
855 }
856 
burn_write_leadin(struct burn_write_opts * o,struct burn_session * s,int first)857 int burn_write_leadin(struct burn_write_opts *o,
858 		       struct burn_session *s, int first)
859 {
860 	struct burn_drive *d = o->drive;
861 	int count;
862 
863 	d->busy = BURN_DRIVE_WRITING_LEADIN;
864 
865 	if (first)
866 		count = 0 - d->alba - 150;
867 	else
868 		count = 4500;
869 
870 	d->progress.start_sector = d->alba;
871 	d->progress.sectors = count;
872 	d->progress.sector = 0;
873 
874 	while (count != 0) {
875 		if (!sector_toc(o, s->track[0]->mode))
876 			return 0;
877 		count--;
878 		d->progress.sector++;
879 	}
880 	d->busy = BURN_DRIVE_WRITING;
881 	return 1;
882 }
883 
burn_write_leadout(struct burn_write_opts * o,int first,unsigned char control,int mode)884 int burn_write_leadout(struct burn_write_opts *o,
885 			int first, unsigned char control, int mode)
886 {
887 	struct burn_drive *d = o->drive;
888 	int count;
889 
890 	d->busy = BURN_DRIVE_WRITING_LEADOUT;
891 
892 	d->rlba = -150;
893 	if (first)
894 		count = 6750;
895 	else
896 		count = 2250;
897 	d->progress.start_sector = d->alba;
898 	d->progress.sectors = count;
899 	d->progress.sector = 0;
900 
901 	while (count != 0) {
902 		if (!sector_lout(o, control, mode))
903 			return 0;
904 		count--;
905 		d->progress.sector++;
906 	}
907 	d->busy = BURN_DRIVE_WRITING;
908 	return 1;
909 }
910 
911 
burn_create_text_packs(struct burn_write_opts * o,struct burn_session * s,int flag)912 static int burn_create_text_packs(struct burn_write_opts *o,
913 					struct burn_session *s,
914 					int flag)
915 {
916 	int ret, num_packs = 0;
917 	unsigned char *text_packs = NULL;
918 
919 	ret = burn_cdtext_from_session(s, &text_packs, &num_packs, 0);
920 	if (ret > 0) {
921 		if (o->text_packs != NULL)
922 			free(o->text_packs);
923 		o->text_packs = text_packs;
924 		o->num_text_packs = num_packs;
925 	}
926 	return(ret);
927 }
928 
929 
burn_write_leadin_cdtext(struct burn_write_opts * o,struct burn_session * s,int flag)930 static int burn_write_leadin_cdtext(struct burn_write_opts *o,
931 					 struct burn_session *s, int flag)
932 {
933 	int ret, i, j, si, lba, sub_cursor = 0, err, write_lba, sectors = 0;
934 	int self_made_text_packs = 0;
935 	unsigned char *subdata = NULL;
936 	struct burn_drive *d = o->drive;
937 	struct buffer *buf = NULL;
938 	enum burn_drive_status was_busy = o->drive->busy;
939 #ifdef Libburn_debug_cd_texT
940 	unsigned char *packs;
941 #endif
942 
943 	if (o->num_text_packs <= 0) {
944 		if (o->text_packs != NULL)
945 			{ret = 1; goto ex;}
946 		/* Try to create CD-TEXT from .cdtext_* of session and track */
947 		ret = burn_create_text_packs(o, s, 0);
948 		self_made_text_packs = 1;
949 		if (ret <= 0)
950 			goto ex;
951 		if (o->num_text_packs <= 0)
952 			{ret = 1; goto ex;}
953 	}
954 
955 	if (!o->no_text_pack_crc_check) {
956 		ret = burn_cdtext_crc_mismatches(o->text_packs,
957 				 o->num_text_packs, 0);
958 		if (ret != 0) {
959 			libdax_msgs_submit(libdax_messenger, -1, 0x0002018f,
960 				LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
961 				"Program error: CD-TEXT pack CRC mismatch",
962 				0, 0);
963 			{ ret = 0; goto ex; }
964 		}
965 	}
966 
967 	d->busy = BURN_DRIVE_WRITING_LEADIN;
968 
969 #ifdef Libburn_debug_cd_texT
970 	packs = o->text_packs;
971 	fprintf(stderr,
972 		"libburn_DEBUG: 8 bit CD-TEXT packs to be transmitted:\n");
973 	for (i = 0; i < 18 * o->num_text_packs; i += 18) {
974 		fprintf(stderr, "%4d :", i / 18);
975 		for (j = 0; j < 18; j++) {
976 			if (j >= 4 && j <= 15 && packs[i + j] >= 32 &&
977 			    packs[i + j] <= 126 && packs[i] != 0x88 &&
978 			    packs[i] != 0x89 && packs[i] != 0x8f)
979 				fprintf(stderr, "  %c", packs[i + j]);
980 			else
981 				fprintf(stderr, " %2.2X", packs[i + j]);
982 		}
983 		fprintf(stderr, "\n");
984 	}
985 #endif /* Libburn_debug_cd_texT */
986 
987 	/* Chop from 8 bit text pack to 6 bit subchannel */
988 	BURN_ALLOC_MEM(subdata, unsigned char, o->num_text_packs * 24);
989 	for (i = 0; i < 18 * o->num_text_packs; i += 3) {
990 		si = i / 3 * 4;
991 		subdata[si + 0] =  (o->text_packs[i + 0] >> 2) & 0x3f;
992 		subdata[si + 1] =  (o->text_packs[i + 0] << 4) & 0x30;
993 		subdata[si + 1] |= (o->text_packs[i + 1] >> 4) & 0x0f;
994 		subdata[si + 2] =  (o->text_packs[i + 1] << 2) & 0x3c;
995 		subdata[si + 2] |= (o->text_packs[i + 2] >> 6) & 0x03;
996 		subdata[si + 3] =  (o->text_packs[i + 2] >> 0) & 0x3f;
997 	}
998 
999 	/* Start at Lead-in address of ATIP and write blocks up to -150 */
1000 	BURN_ALLOC_MEM(buf, struct buffer, 1);
1001 	write_lba = d->start_lba;
1002 	for (lba = d->start_lba; lba < -150; lba++) {
1003 		/* Collect subdata in buf */
1004 		for (j = 0; j < 4; j++) {
1005 			memcpy(buf->data + buf->bytes,
1006 				subdata + sub_cursor * 24, 24);
1007 			sub_cursor = (sub_cursor + 1) % o->num_text_packs;
1008 			buf->bytes += 24;
1009 		}
1010 		buf->sectors++;
1011 		sectors++;
1012 
1013 		/* When full or last sector : perform WRITE */
1014 		if (buf->bytes + 96 >= 32768 || lba == -151) {
1015 
1016 #ifdef Libburn_debug_cd_texT
1017 			fprintf(stderr,
1018 			    "libburn_DEBUG: 6 bit data to be transmitted:\n");
1019 			for (i = 0; i < buf->bytes; i += 24) {
1020 				fprintf(stderr, "%4d :", i / 24);
1021 				for (j = 0; j < 24; j++)
1022 					fprintf(stderr, " %2.2X",
1023 						buf->data[i + j]);
1024 				fprintf(stderr, "\n");
1025 			}
1026 #endif /* Libburn_debug_cd_texT */
1027 
1028 			err = d->write(d, write_lba, buf);
1029 			if (err == BE_CANCELLED)
1030 				{ ret = 0; goto ex; }
1031 			write_lba += sectors;
1032 			sectors = buf->sectors = buf->bytes = 0;
1033 		}
1034 	}
1035 	ret = 1;
1036 ex:;
1037 	if (self_made_text_packs) {
1038 		if (o->text_packs != NULL)
1039 			free(o->text_packs);
1040 		o->text_packs = NULL;
1041 		o->num_text_packs = 0;
1042 	}
1043 	BURN_FREE_MEM(subdata);
1044 	BURN_FREE_MEM(buf);
1045 	d->busy = was_busy;
1046 	return ret;
1047 }
1048 
1049 
burn_write_session(struct burn_write_opts * o,struct burn_session * s)1050 int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
1051 {
1052 	struct burn_drive *d = o->drive;
1053 	int i, ret;
1054 
1055 	if (o->write_type == BURN_WRITE_SAO) {
1056 		ret = burn_write_leadin_cdtext(o, s, 0);
1057 		if (ret <= 0)
1058 			goto ex;
1059 	}
1060 	d->rlba = 0;
1061 	for (i = 0; i < s->tracks; i++) {
1062 		if (!burn_write_track(o, s, i))
1063 			{ ret = 0; goto ex; }
1064 	}
1065 
1066 	/* ts A61103 */
1067 	ret = 1;
1068 ex:;
1069 	if (o->write_type == BURN_WRITE_TAO)
1070 		burn_write_close_session(o);
1071 	return ret;
1072 }
1073 
1074 
1075 /* ts A61218 : outsourced from burn_write_track() */
burn_disc_init_track_status(struct burn_write_opts * o,struct burn_session * s,struct burn_track * t,int tnum,int sectors)1076 int burn_disc_init_track_status(struct burn_write_opts *o,
1077 				struct burn_session *s, struct burn_track *t,
1078 				int tnum, int sectors)
1079 {
1080 	struct burn_drive *d = o->drive;
1081 
1082 	/* Update progress */
1083 
1084 	d->progress.start_sector = d->nwa;
1085 
1086 	d->progress.sectors = sectors;
1087 	d->progress.sector = 0;
1088 
1089 	/* ts A60831: added tnum-line, extended print message on proposal
1090            by bonfire-app@wanadoo.fr in http://libburn.pykix.org/ticket/58 */
1091         d->progress.track = tnum;
1092 
1093 	/* ts B20113 */
1094 	d->progress.indices = t->indices;
1095 	d->progress.index = 0;
1096 	if (d->progress.indices > 1)
1097 		if (t->index[0] == 0x7fffffff)
1098 			d->progress.index = 1;
1099 
1100 	/* ts A61102 */
1101 	d->busy = BURN_DRIVE_WRITING;
1102 
1103 	return 1;
1104 }
1105 
1106 
burn_write_track(struct burn_write_opts * o,struct burn_session * s,int tnum)1107 int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
1108 		      int tnum)
1109 {
1110 	struct burn_track *t = s->track[tnum];
1111 	struct burn_drive *d = o->drive;
1112 	int i, tmp = 0, open_ended = 0, ret= 0, nwa, lba;
1113 	int sectors;
1114 	char msg[160];
1115 
1116 	d->rlba = -150;
1117 
1118 /* XXX for tao, we don't want the pregaps  but still want post? */
1119 	if (o->write_type != BURN_WRITE_TAO) {
1120 
1121 		/* ts A61102 */
1122 		d->busy = BURN_DRIVE_WRITING_PREGAP;
1123 
1124 		if (t->pregap1)
1125 			d->rlba += 75;
1126 		if (t->pregap2)
1127 			d->rlba += t->pregap2_size;
1128 
1129 		if (t->pregap1) {
1130 
1131 			struct burn_track *pt;
1132 			/* ts A70121 : Removed pseudo suicidal initializer
1133 				 = s->track[tnum - 1];
1134 			*/
1135 
1136 			if (tnum == 0) {
1137 
1138 				/* ts A70121 : This is not possible because
1139 				   track 1 cannot have a pregap at all.
1140 				   MMC-5 6.33.3.2 precribes a mandatory pause
1141 				   prior to any track 1. Pre-gap is prescribed
1142 				   for mode changes like audio-to-data.
1143 				   To set burn_track.pregap1 for track 1 is
1144 				   kindof a dirty hack.
1145 				*/
1146 
1147 				printf("first track should not have a pregap1\n");
1148 				pt = t;
1149 			} else
1150 				pt = s->track[tnum - 1]; /* ts A70121 */
1151 			for (i = 0; i < 75; i++)
1152 				if (!sector_pregap(o, t->entry->point,
1153 					           pt->entry->control, pt->mode))
1154 					{ ret = 0; goto ex; }
1155 		}
1156 		if (t->pregap2)
1157 			for (i = 0; i < t->pregap2_size; i++)
1158 				if (!sector_pregap(o, t->entry->point,
1159 					           t->entry->control, t->mode))
1160 					{ ret = 0; goto ex; }
1161 
1162 		/* ts B20113 : Flush buffer to avoid influence pregap
1163 		               on track counter */
1164 		ret = sector_write_buffer(d, NULL, 0);
1165 		if (ret <= 0)
1166 			goto ex;
1167 
1168 	} else {
1169 		o->control = t->entry->control;
1170 		d->send_write_parameters(d, s, tnum, o);
1171 
1172 		/* ts A61103 */
1173 		ret = d->get_nwa(d, -1, &lba, &nwa);
1174 
1175 		/* ts A70213: CD-TAO: eventually expand size of track to max */
1176 		burn_track_apply_fillup(t, d->media_capacity_remaining, 0);
1177 
1178 		/* <<< */
1179 		sprintf(msg,
1180 	"TAO pre-track %2.2d : get_nwa(%d)=%d, d=%d , demand=%.f , cap=%.f\n",
1181 			tnum+1, nwa, ret, d->nwa,
1182 			(double) burn_track_get_sectors_2(t, 1) * 2048.0,
1183 			(double) d->media_capacity_remaining);
1184 		libdax_msgs_submit(libdax_messenger, d->global_index,
1185 				 0x00000002,
1186 				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1187 				msg, 0, 0);
1188 
1189 		/* ts A91003 */
1190 		if (nwa < d->nwa) {
1191 			libdax_msgs_submit(libdax_messenger, d->global_index,
1192 				0x00020173,
1193 				LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1194 			   "Drive tells NWA smaller than last written address",
1195 				0, 0);
1196 			d->sync_cache(d);
1197 			return 0;
1198 		}
1199 		d->nwa = nwa;
1200 
1201 	}
1202 
1203 /* user data */
1204 
1205 	sectors = burn_track_get_sectors_2(t, 1);
1206 	open_ended = burn_track_is_open_ended(t);
1207 
1208 	burn_disc_init_track_status(o, s, t, tnum, sectors);
1209 
1210 	/* ts A61030 : this cannot happen. tnum is always < s->tracks */
1211 	if (tnum == s->tracks)
1212 		tmp = sectors > 150 ? 150 : sectors;
1213 
1214 	for (i = 0; open_ended || i < sectors - tmp; i++) {
1215 
1216 		/* ts A61023 : http://libburn.pykix.org/ticket/14
1217                                From time to time inquire drive buffer */
1218 		if ((i%64)==0)
1219 			d->read_buffer_capacity(d);
1220 
1221 		if (!sector_data(o, t, 0))
1222 			{ ret = 0; goto ex; }
1223 
1224 		/* ts A61031 */
1225 		if (open_ended) {
1226 			d->progress.sectors = sectors = i;
1227                         if (burn_track_is_data_done(t))
1228 	break;
1229 		}
1230 
1231 		/* update current progress */
1232 		d->progress.sector++;
1233 	}
1234 	for (; i < sectors; i++) {
1235 
1236 		/* ts A61030: program execution never gets to this point */
1237 		fprintf(stderr,"LIBBURN_DEBUG: TNUM=%d  TRACKS=%d  TMP=%d\n",
1238 			tnum, s->tracks, tmp);
1239 
1240 		/* ts A61023 */
1241 		if ((i%64)==0)
1242 			d->read_buffer_capacity(d);
1243 
1244 		if (!sector_data(o, t, 1))
1245 			{ ret = 0; goto ex; }
1246 
1247 		/* update progress */
1248 		d->progress.sector++;
1249 	}
1250 
1251 	/* ts B20113 : Flush buffer to get buffered bytes assigned to the
1252 	               track counter */
1253 	ret = sector_write_buffer(d, t, 0);
1254 	if (ret <= 0)
1255 		goto ex;
1256 
1257 	if (t->postgap && o->write_type != BURN_WRITE_TAO) {
1258 		for (i = 0; i < t->postgap_size; i++)
1259 			if (!sector_postgap(o, t->entry->point,
1260 						 t->entry->control, t->mode))
1261 				{ ret = 0; goto ex; }
1262 		ret = sector_write_buffer(d, NULL, 0);
1263 		if (ret <= 0)
1264 			goto ex;
1265 	}
1266 
1267 	/* ts A61103 */
1268 	ret = 1;
1269 ex:;
1270 	if (d->cancel)
1271 		burn_source_cancel(t->source);
1272 	if (o->write_type == BURN_WRITE_TAO) {
1273 
1274 		/* ts A71002 */
1275 		if (!burn_write_flush_buffer(o, t))
1276 			ret = 0;
1277 
1278 		/* Ensure that at least 600 kB get written */
1279 		burn_write_track_minsize(o, s, tnum);
1280 		d->sync_cache(d);
1281 
1282 		/* ts A61030 */
1283 		/* ts A91003 :
1284 		   At least in simulation mode this causes NWA=0 for the
1285 		   next track. cdrecord does not use CLOSE TRACK at all but
1286 		   ends the tracks by SYNCHRONIZE CACHE alone.
1287 		*/
1288 		/* ts A91202 :
1289 		   Peng Shao reports that his LG GH22LS30 issues an SCSI error
1290 		   on CLOSE TRACK even in non-dummy mode. So i better give up
1291 		   this gesture which seems not be needed by any drive.
1292 			if (!o->simulate)
1293 				if (burn_write_close_track(o, s, tnum) <= 0)
1294 					ret = 0;
1295 		*/
1296 	}
1297 	return ret;
1298 }
1299 
1300 /* ts A61009 */
1301 /* @param flag bit1 = do not libdax_msgs_submit() */
burn_disc_write_is_ok(struct burn_write_opts * o,struct burn_disc * disc,int flag)1302 int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
1303 			int flag)
1304 {
1305 	int i, t;
1306 	char msg[80];
1307 
1308 	for (i = 0; i < disc->sessions; i++)
1309 		for (t = 0; t < disc->session[i]->tracks; t++)
1310 			if (sector_headers_is_ok(
1311 				o, disc->session[i]->track[t]->mode) != 1)
1312 				goto bad_track_mode_found;
1313 	return 1;
1314 bad_track_mode_found:;
1315 	sprintf(msg, "Unsuitable track mode 0x%x in track %d of session %d",
1316 		disc->session[i]->track[t]->mode, i+1, t+1);
1317 	if (!(flag & 2))
1318 		libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
1319 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1320 				msg, 0, 0);
1321 	return 0;
1322 }
1323 
1324 
1325 /* ts A61218 : outsourced from burn_disc_write_sync() */
burn_disc_init_write_status(struct burn_write_opts * o,struct burn_disc * disc)1326 int burn_disc_init_write_status(struct burn_write_opts *o,
1327 				struct burn_disc *disc)
1328 {
1329 	struct burn_drive *d = o->drive;
1330 	struct burn_track *t = NULL;
1331 	int sx, tx, ret;
1332 
1333 	d->cancel = 0;
1334 
1335 #ifdef Libburn_reset_progress_asynC
1336 	/* <<< This is now done in async.c */
1337 	/* init progress before showing the state */
1338 	d->progress.session = 0;
1339 	d->progress.sessions = disc->sessions;
1340 	d->progress.track = 0;
1341 	d->progress.tracks = disc->session[0]->tracks;
1342 	/* TODO: handle indices */
1343 	d->progress.index = 0;
1344 	d->progress.indices = disc->session[0]->track[0]->indices;
1345 	/* TODO: handle multissession discs */
1346 	/* XXX: sectors are only set during write track */
1347 	d->progress.start_sector = 0;
1348 	d->progress.sectors = 0;
1349 	d->progress.sector = 0;
1350 	d->progress.track = 0;
1351 #endif /* Libburn_reset_progress_asynC */
1352 
1353 	/* ts A61023 */
1354 	d->progress.buffer_capacity = 0;
1355 	d->progress.buffer_available = 0;
1356 	d->progress.buffered_bytes = 0;
1357 	d->progress.buffer_min_fill = 0xffffffff;
1358 
1359 	/* ts A70711 */
1360 	d->pessimistic_buffer_free = 0;
1361 	d->pbf_altered = 0;
1362 	d->pessimistic_writes = 0;
1363 	d->waited_writes = 0;
1364 	d->waited_tries = 0;
1365 	d->waited_usec = 0;
1366 
1367 	/* Set eventual media fill up for last track only */
1368 	for (sx = 0; sx < disc->sessions; sx++)
1369 		for (tx = 0 ; tx < disc->session[sx]->tracks; tx++) {
1370 			t = disc->session[sx]->track[tx];
1371 			burn_track_set_fillup(t, 0);
1372 		}
1373 	if (o->fill_up_media && t != NULL)
1374 		burn_track_set_fillup(t, 1);
1375 
1376 	d->was_feat21h_failure = 0;
1377 	if(d->write_opts != NULL)
1378 		burn_write_opts_free(d->write_opts);
1379 	ret = burn_write_opts_clone(o, &(d->write_opts), 0);
1380 	if (ret <= 0)
1381 		return ret;
1382 	d->write_retry_count = 0;
1383 
1384 	d->busy = BURN_DRIVE_WRITING;
1385 
1386 	return 1;
1387 }
1388 
1389 
precheck_write_is_audio(struct burn_disc * disc,int flag)1390 static int precheck_write_is_audio(struct burn_disc *disc, int flag)
1391 {
1392 	struct burn_session **sessions;
1393 	int num_sessions, i, j;
1394 
1395 	sessions = burn_disc_get_sessions(disc, &num_sessions);
1396 	for (i = 0; i < num_sessions; i++)
1397 		for (j = 0; j < sessions[i]->tracks; j++)
1398 			if (!(sessions[i]->track[j]->mode & BURN_AUDIO))
1399 				return 0;
1400 	return 1;
1401 }
1402 
1403 
precheck_disc_has_cdtext(struct burn_disc * disc,int flag)1404 static int precheck_disc_has_cdtext(struct burn_disc *disc, int flag)
1405 {
1406 	struct burn_session **sessions;
1407 	int num_sessions, i, ret;
1408 
1409 	sessions = burn_disc_get_sessions(disc, &num_sessions);
1410 	for (i = 0; i < num_sessions; i++) {
1411 		ret = burn_cdtext_from_session(sessions[i], NULL, NULL, 1);
1412 		if (ret > 0)
1413 			return 1;
1414 	}
1415 	return 0;
1416 }
1417 
1418 
1419 /* ts A70219 : API */
burn_precheck_write(struct burn_write_opts * o,struct burn_disc * disc,char reasons[BURN_REASONS_LEN],int silent)1420 int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
1421 				 char reasons[BURN_REASONS_LEN], int silent)
1422 {
1423 	enum burn_write_types wt;
1424 	struct burn_drive *d = o->drive;
1425 	char *msg = NULL, *reason_pt;
1426 	int no_media = 0, ret, has_cdtext, is_bd_pow = 0;
1427 
1428 	reason_pt= reasons;
1429 	reasons[0] = 0;
1430 
1431 	if (d->drive_role == 0 || d->drive_role == 4) {
1432 		if (d->drive_role == 0)
1433 			sprintf(reasons,
1434 			       "DRIVE: is a virtual placeholder (null-drive)");
1435 		else
1436 			sprintf(reasons, "DRIVE: read-only pseudo drive");
1437 		no_media = 1;
1438 		goto ex;
1439 	}
1440 
1441 	/* check write mode against write job */
1442 	wt = burn_write_opts_auto_write_type(o, disc, reasons, 1);
1443 	if (wt == BURN_WRITE_NONE) {
1444 		if (strncmp(reasons, "MEDIA: ", 7)==0)
1445 			no_media = 1;
1446 		goto ex;
1447 	}
1448 
1449 	sprintf(reasons, "%s: ", d->current_profile_text);
1450 	reason_pt= reasons + strlen(reasons);
1451 	if (d->status == BURN_DISC_UNSUITABLE)
1452 		goto unsuitable_profile;
1453 	if (o->num_text_packs > 0) {
1454 		has_cdtext = 1;
1455 	} else {
1456 		has_cdtext = precheck_disc_has_cdtext(disc, 0);
1457 	}
1458 	if (has_cdtext > 0) {
1459 		if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
1460 			ret = precheck_write_is_audio(disc, 0);
1461 			if (ret <= 0)
1462 				strcat(reasons,
1463 			"CD-TEXT supported only with pure audio CD media, ");
1464 		} else {
1465 			strcat(reasons,
1466 				"CD-TEXT supported only with CD media, ");
1467 		}
1468 	}
1469 	if (d->drive_role == 2 || d->drive_role == 5 ||
1470 		d->current_profile == 0x1a || d->current_profile == 0x12 ||
1471 		d->current_profile == 0x43) {
1472 		/* DVD+RW , DVD-RAM , BD-RE, emulated drive on stdio file */
1473 		if (o->start_byte >= 0 && (o->start_byte % 2048))
1474 			strcat(reasons,
1475 			 "write start address not properly aligned to 2048, ");
1476 	} else if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
1477 		/* CD-R , CD-RW */
1478 		if (!burn_disc_write_is_ok(o, disc, (!!silent) << 1))
1479 			strcat(reasons, "unsuitable track mode found, ");
1480 		if (o->start_byte >= 0)
1481 			strcat(reasons, "write start address not supported, ");
1482 		if (o->num_text_packs > 0) {
1483 			if (o->write_type != BURN_WRITE_SAO)
1484 				strcat(reasons,
1485 				"CD-TEXT supported only with write type SAO, ");
1486 			if (d->start_lba == -2000000000)
1487 				strcat(reasons,
1488 				"No Lead-in start address known with CD-TEXT, ");
1489 		}
1490 	} else if (d->current_profile == 0x13) {
1491 		/* DVD-RW Restricted Overwrite */
1492 		if (o->start_byte >= 0 && (o->start_byte % 32768))
1493 			strcat(reasons,
1494 			  "write start address not properly aligned to 32k, ");
1495 	} else if (d->drive_role == 3 ||
1496 		   d->current_profile == 0x11 || d->current_profile == 0x14 ||
1497 	           d->current_profile == 0x15 ||
1498 	           d->current_profile == 0x1b || d->current_profile == 0x2b ||
1499 		   d->current_profile == 0x41) {
1500 		/* DVD-R* Sequential , DVD+R[/DL] , BD-R,
1501 		   sequential stdio "drive" */
1502 		if (o->start_byte >= 0)
1503 			strcat(reasons, "write start address not supported, ");
1504 
1505 		is_bd_pow = burn_drive_get_bd_r_pow(d);
1506 		if (is_bd_pow && !silent)
1507 			libdax_msgs_submit(libdax_messenger, d->global_index,
1508 				0x0002011e,
1509 				LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
1510 			   "Unsuitable media detected: BD-R formatted to POW.",
1511 				0, 0);
1512 		if (is_bd_pow) {
1513 			strcat(reasons,
1514 				"unsuitable media formatting POW detected, ");
1515 			return 0;
1516 		}
1517 
1518 	} else {
1519 unsuitable_profile:;
1520 		msg = calloc(1, 160);
1521 		if (msg != NULL && !silent) {
1522 			sprintf(msg,
1523 			    "Unsuitable media detected. Profile %4.4Xh  %s",
1524 			    d->current_profile, d->current_profile_text);
1525 			libdax_msgs_submit(libdax_messenger, d->global_index,
1526 				0x0002011e,
1527 				LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
1528 				msg, 0, 0);
1529 		}
1530 		if (msg != NULL)
1531 			free(msg);
1532 		strcat(reasons, "no suitable media profile detected, ");
1533 		return 0;
1534 	}
1535 ex:;
1536 	if (reason_pt[0]) {
1537 		if (no_media) {
1538 			if (!silent)
1539 				libdax_msgs_submit(libdax_messenger,
1540 				  d->global_index, 0x0002013a,
1541 				  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1542 				  "No suitable media detected", 0, 0);
1543 			return -1;
1544 		}
1545 		if (!silent)
1546 			libdax_msgs_submit(libdax_messenger,
1547 				  d->global_index, 0x00020139,
1548 				  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
1549 				  "Write job parameters are unsuitable", 0, 0);
1550 		return 0;
1551 	}
1552 	return 1;
1553 }
1554 
1555 
1556 /* ts A70129 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
burn_disc_open_track_dvd_minus_r(struct burn_write_opts * o,struct burn_session * s,int tnum)1557 int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o,
1558 					struct burn_session *s, int tnum)
1559 {
1560 	struct burn_drive *d = o->drive;
1561 	char *msg = NULL;
1562 	int ret, lba, nwa;
1563 	off_t size;
1564 
1565 	BURN_ALLOC_MEM(msg, char, 160);
1566 	d->send_write_parameters(d, NULL, -1, o);
1567 	ret = d->get_nwa(d, -1, &lba, &nwa);
1568 	sprintf(msg,
1569 		"DVD pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d",
1570 		tnum+1, nwa, ret, d->nwa);
1571 	libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
1572 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0);
1573 	if (nwa > d->nwa)
1574 		d->nwa = nwa;
1575 	/* ts A70214 : eventually adjust already expanded size of track */
1576 	burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);
1577 
1578 #ifdef Libburn_pioneer_dvr_216d_with_opC
1579 	fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : num_opc_tables = %d\n", d->num_opc_tables);
1580 	if (d->num_opc_tables <= 0 && !o->simulate) {
1581 		fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : performing OPC\n");
1582 		d->perform_opc(d);
1583 		fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : done\n");
1584 	}
1585 #endif
1586 
1587 #ifdef Libburn_pioneer_dvr_216d_get_evenT
1588 	mmc_get_event(d);
1589 #endif
1590 
1591 	if (o->write_type == BURN_WRITE_SAO) { /* DAO */
1592 		size = ((off_t) burn_track_get_sectors_2(s->track[tnum], 1))
1593 			* (off_t) 2048;
1594 
1595  		/* Eventually round track size up to write chunk */
1596 		if (o->obs_pad && (size % o->obs))
1597 			size += (off_t) (o->obs - (size % o->obs));
1598 
1599 		ret = d->reserve_track(d, size);
1600 		if (ret <= 0) {
1601 			sprintf(msg, "Cannot reserve track of %.f bytes",
1602 				(double) size);
1603 			libdax_msgs_submit(libdax_messenger, d->global_index,
1604 				0x00020138,
1605 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1606 				msg, 0, 0);
1607 			{ret = 0; goto ex;}
1608 		}
1609 	}
1610 	ret = 1;
1611 ex:;
1612 	BURN_FREE_MEM(msg);
1613 	return ret;
1614 }
1615 
1616 
1617 /* ts A70226 */
burn_disc_open_track_dvd_plus_r(struct burn_write_opts * o,struct burn_session * s,int tnum)1618 int burn_disc_open_track_dvd_plus_r(struct burn_write_opts *o,
1619 					struct burn_session *s, int tnum)
1620 {
1621 	struct burn_drive *d = o->drive;
1622 	char *msg = NULL;
1623 	int ret, lba, nwa;
1624 	off_t size;
1625 
1626 	BURN_ALLOC_MEM(msg, char, 160);
1627 	ret = d->get_nwa(d, -1, &lba, &nwa);
1628 	sprintf(msg,
1629 		"DVD+R pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d",
1630 		tnum+1, nwa, ret, d->nwa);
1631 	libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
1632 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0);
1633 	if (nwa > d->nwa)
1634 		d->nwa = nwa;
1635 	/* ts A70214 : eventually adjust already expanded size of track */
1636 	burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);
1637 
1638 	if (o->write_type == BURN_WRITE_SAO &&
1639 	    ! burn_track_is_open_ended(s->track[tnum])) {
1640  		/* Reserve track */
1641 		size = ((off_t) burn_track_get_sectors_2(s->track[tnum], 1))
1642 			* (off_t) 2048;
1643 		if (o->obs_pad) {
1644 	 		/* Round track size up to write chunk size */
1645 			/* o->obs should be 32k or 64k already. But 32k
1646 			   alignment was once performed in d->reserve_track()*/
1647 			if (o->obs % 32768)
1648 				o->obs += 32768 - (o->obs % 32768);
1649 			if (size % o->obs)
1650 				size += (off_t) (o->obs - (size % o->obs));
1651 		}
1652 
1653 		/* <<< Only for now until the first DVD+R succeeded */
1654 		if (!o->obs_pad) {
1655 			sprintf(msg, "Program error: encountered DVD+R without chunk padding");
1656 			libdax_msgs_submit(libdax_messenger, d->global_index,
1657 				0x00000004,
1658 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1659 				msg, 0, 0);
1660 			{ret = 0; goto ex;}
1661 		}
1662 
1663 		ret = d->reserve_track(d, size);
1664 		if (ret <= 0) {
1665 			sprintf(msg, "Cannot reserve track of %.f bytes",
1666 				(double) size);
1667 			libdax_msgs_submit(libdax_messenger, d->global_index,
1668 				0x00020138,
1669 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1670 				msg, 0, 0);
1671 			{ret = 0; goto ex;}
1672 		}
1673 	}
1674 	ret = 1;
1675 ex:;
1676 	BURN_FREE_MEM(msg);
1677 	return ret;
1678 }
1679 
1680 
1681 /* ts A70129 */
burn_disc_close_track_dvd_minus_r(struct burn_write_opts * o,int tnum)1682 int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o, int tnum)
1683 {
1684 	struct burn_drive *d = o->drive;
1685 	char msg[80];
1686 
1687 	/* only with Incremental writing */
1688 	if (o->write_type != BURN_WRITE_TAO)
1689 		return 2;
1690 
1691 	sprintf(msg, "Closing track %2.2d  (absolute track number %d)",
1692 		tnum + 1, d->last_track_no);
1693 	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
1694 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
1695 
1696 	d->busy = BURN_DRIVE_CLOSING_SESSION;
1697 	/* Ignoring tnum here and hoping that d->last_track_no is correct */
1698 	d->close_track_session(d, 0, d->last_track_no); /* CLOSE TRACK, 001b */
1699 	d->busy = BURN_DRIVE_WRITING;
1700 	d->last_track_no++;
1701 	return 1;
1702 }
1703 
1704 
1705 /* ts A70229 */
burn_disc_finalize_dvd_plus_r(struct burn_write_opts * o)1706 int burn_disc_finalize_dvd_plus_r(struct burn_write_opts *o)
1707 {
1708 	struct burn_drive *d = o->drive;
1709 	char msg[40 + 80]; /* filltext + profile */
1710 
1711 	sprintf(msg, "Finalizing %s ...",
1712 		d->current_profile_text);
1713 	libdax_msgs_submit(libdax_messenger, d->global_index,
1714 			0x00000002,
1715 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1716 			msg, 0, 0);
1717 
1718 	if(d->current_profile == 0x41) { /* BD-R */
1719 		/* CLOSE SESSION, 110b, Finalize Disc */
1720 		d->close_track_session(d, 3, 0);  /* (3<<1)|0 = 6 */
1721 	} else {
1722 		/* CLOSE SESSION, 101b, Finalize with minimal radius */
1723 		d->close_track_session(d, 2, 1);  /* (2<<1)|1 = 5 */
1724 	}
1725 
1726 	sprintf(msg, "... finalizing %s done               ",
1727 		d->current_profile_text);
1728 	libdax_msgs_submit(libdax_messenger, d->global_index,
1729 			0x00000002,
1730 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1731 			msg, 0, 0);
1732 
1733 	return 1;
1734 }
1735 
1736 
1737 /* ts A70226 */
burn_disc_close_track_dvd_plus_r(struct burn_write_opts * o,int tnum,int is_last_track)1738 int burn_disc_close_track_dvd_plus_r(struct burn_write_opts *o,
1739 			int tnum, int is_last_track)
1740 {
1741 	struct burn_drive *d = o->drive;
1742 	char msg[80];
1743 
1744 	sprintf(msg,
1745 		"Closing track %2.2d  (absolute track and session number %d)",
1746 		tnum + 1, d->last_track_no);
1747 	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
1748 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
1749 
1750 	d->busy = BURN_DRIVE_CLOSING_SESSION;
1751 	d->close_track_session(d, 0, d->last_track_no); /* CLOSE TRACK, 001b */
1752 
1753 	/* Each session becomes a single logical track. So to distinguish them,
1754 	   it is mandatory to close the session together with each track. */
1755 
1756 	if (is_last_track && !o->multi)
1757 		burn_disc_finalize_dvd_plus_r(o);
1758 	else
1759  		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
1760 	d->busy = BURN_DRIVE_WRITING;
1761 	d->last_track_no++;
1762 	return 1;
1763 }
1764 
1765 
1766 /* <<<
1767 #define Libburn_simplified_dvd_chunk_transactioN 1
1768 */
1769 
1770 #ifdef Libburn_simplified_dvd_chunk_transactioN
1771 
1772 /* ts A91114 : EXPERIMENTAL, NOT COMPLETELY IMPLEMENTED
1773 
1774    Simplified data transmission for DVD. libburn via GNU/Linux USB is 30 %
1775    slower than growisofs or cdrecord when transmitting 32 KB chunks.
1776    With 64 KB chunks it is 20% faster than the competitors.
1777    No heavy CPU load is visible but there might be subtle race conditions in
1778    the USB driver which work better with shorter time gaps between WRITE
1779    commands.
1780 
1781    Insight: It is actually about the interference of track source reading
1782             with SCSI writing via USB. growisofs reads with O_DIRECT into a
1783             mmap()ed buffer. When doing the same, libburn with 32 KB chunks
1784             reaches similar write speed.
1785             On the other hand, 64 KB chunks are 20% faster than that and
1786             are not improved by reading O_DIRECT.
1787 
1788             O_DIRECT is a property of the input fd of struct burn_source.
1789             It can only be done with properly aligned memory and with aligned
1790             read size. Alignment size is file system system specific.
1791             System call
1792                 mmap(NULL, (size_t) buffer_size, PROT_READ | PROT_WRITE,
1793                      MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0);
1794             is supposed to allocate a properly aligned buffer.
1795             64 KB is supposed to be a safe size.
1796             Actually mmap() seems to be the main cause for a positive effect
1797             of O_DIRECT.
1798 
1799    This simplified transmission function did not bring visible benefit.
1800    So for now it is not worth to teach it all applicable details of old
1801    CD sector oriented transmission.
1802 
1803    @return 1= ok, go on , 2= no input with track->open_ended = nothing written
1804            <= 0 = error
1805 */
transact_dvd_chunk(struct burn_write_opts * opts,struct burn_track * track)1806 static int transact_dvd_chunk(struct burn_write_opts *opts,
1807 				 struct burn_track *track)
1808 {
1809 	int curr = 0, valid, err;
1810 	struct burn_drive *d = opts->drive;
1811         struct buffer *out = d->buffer;
1812 	unsigned char *data = out->data;
1813 
1814 #ifdef Libburn_log_in_and_out_streaM
1815 	/* ts A61031 */
1816 	static int tee_fd= -1;
1817 	if(tee_fd==-1)
1818 		tee_fd= open("/tmp/libburn_sg_readin",
1819 				O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
1820 				S_IRUSR | S_IWUSR);
1821 #endif /* Libburn_log_in_and_out_streaM */
1822 
1823 
1824 	/* Read a chunk full of data */
1825 
1826 	/* ??? Do we have offset padding ? >>> First produce offset padding */;
1827 
1828 	/*  <<<< */
1829 	if (0 && !track->eos) {
1830 		for (curr = 0; curr < opts->obs; curr += 2048) {
1831 			if (track->source->read != NULL)
1832 				valid = track->source->read(track->source,
1833 						data + curr, 2048);
1834 			else
1835 				valid = track->source->read_xt(track->source,
1836 						data + curr, 2048);
1837 			if (valid <= 0) {
1838 				track->eos = 1;
1839 		break;
1840 			}
1841 			track->sourcecount += valid;
1842 
1843 #ifdef Libburn_log_in_and_out_streaM
1844 			if(tee_fd!=-1 && valid>0) {
1845 				write(tee_fd, data + curr, valid);
1846 			}
1847 #endif /* Libburn_log_in_and_out_streaM */
1848 
1849 		}
1850 	} else if (!track->eos){
1851 		valid = track->source->read(track->source, data, opts->obs);
1852 		if (valid <= 0) {
1853 			track->eos = 1;
1854 		} else {
1855 			track->sourcecount += valid;
1856 			curr = valid;
1857 
1858 #ifdef Libburn_log_in_and_out_streaM
1859 			if(tee_fd!=-1 && valid>0) {
1860 				write(tee_fd, data, valid);
1861 			}
1862 #endif /* Libburn_log_in_and_out_streaM */
1863 		}
1864 	}
1865 	if (curr == 0 && track->open_ended) {
1866 
1867 		/* >>> allow tail padding */;
1868 
1869 		return 2;
1870 	}
1871 	if (curr < opts->obs)
1872 		memset(data + curr , 0, opts->obs - curr);
1873 
1874 	/* Write chunk */
1875 	out->bytes = opts->obs;
1876 	out->sectors = out->bytes / 2048;
1877 	err = d->write(d, d->nwa, out);
1878 	if (err == BE_CANCELLED)
1879 		return 0;
1880 	track->writecount += out->bytes;
1881 	track->written_sectors += out->sectors;
1882 	d->progress.buffered_bytes += out->bytes;
1883 	d->nwa += out->sectors;
1884 	out->bytes = 0;
1885 	out->sectors = 0;
1886 
1887 	return 1;
1888 }
1889 
1890 #endif /* Libburn_simplified_dvd_chunk_transactioN */
1891 
1892 
1893 /* ts A61218 - A81208 */
burn_dvd_write_track(struct burn_write_opts * o,struct burn_session * s,int tnum,int is_last_track)1894 int burn_dvd_write_track(struct burn_write_opts *o,
1895 			struct burn_session *s, int tnum, int is_last_track)
1896 {
1897 	struct burn_track *t = s->track[tnum];
1898 	struct burn_drive *d = o->drive;
1899 	struct buffer *out = d->buffer;
1900 	int sectors;
1901 	int i, open_ended = 0, ret= 0, is_flushed = 0, track_open = 0;
1902 	int first_buf_cap = 0, further_cap = 0, buf_cap_step = 1024;
1903 
1904 	/* ts A70213 : eventually expand size of track to max */
1905 	burn_track_apply_fillup(t, d->media_capacity_remaining, 0);
1906 
1907 	/* ts C00806 : Consider the track state changed by try to open */
1908 	d->medium_state_changed = 1;
1909 
1910 	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
1911 	    d->current_profile == 0x15) {
1912 		/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
1913 		ret = burn_disc_open_track_dvd_minus_r(o, s, tnum);
1914 		if (ret <= 0)
1915 			goto ex;
1916 		/* Pioneer DVR-216D rev 1.09 hates multiple buffer inquiries
1917 		   before the drive buffer is full.
1918 		*/
1919 		first_buf_cap = 0;
1920 		further_cap = -1;
1921 	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
1922 		/* DVD+R , DVD+R/DL */
1923 		ret = burn_disc_open_track_dvd_plus_r(o, s, tnum);
1924 		if (ret <= 0)
1925 			goto ex;
1926 	} else if (d->current_profile == 0x41) {
1927 		/* BD-R SRM */
1928 		ret = burn_disc_open_track_dvd_plus_r(o, s, tnum);
1929 		if (ret <= 0)
1930 			goto ex;
1931 	}
1932 	track_open = 1;
1933 
1934 	sectors = burn_track_get_sectors_2(t, 1);
1935 	open_ended = burn_track_is_open_ended(t);
1936 
1937 	/* (offset padding is done within sector_data()) */
1938 
1939 	burn_disc_init_track_status(o, s, t, tnum, sectors);
1940 	for (i = 0; open_ended || i < sectors; i++) {
1941 
1942 		/* From time to time inquire drive buffer */
1943 		/* ts A91110: Eventually avoid to do this more than once
1944 		              before the drive buffer is full. See above DVD-
1945 		*/
1946 		if (i == first_buf_cap ||
1947 		   ((i % buf_cap_step) == 0 &&
1948 		    (i >= further_cap || further_cap < 0))) {
1949 			d->read_buffer_capacity(d);
1950 			if (further_cap < 0)
1951 				further_cap =
1952 			 	    d->progress.buffer_capacity / 2048 + 128;
1953 		}
1954 
1955 #ifdef Libburn_simplified_dvd_chunk_transactioN
1956 
1957 		ret = transact_dvd_chunk(o, t);
1958 		if (ret <= 0)
1959 			{ret = 0; goto ex;}
1960 		i += o->obs / 2048 - 1;
1961 		d->progress.sector += o->obs / 2048 - 1;
1962 #else
1963 		/* transact a (CD sized) sector */
1964 		if (!sector_data(o, t, 0))
1965 			{ ret = 0; goto ex; }
1966 #endif
1967 
1968 		if (open_ended) {
1969 			d->progress.sectors = sectors = i;
1970                         if (burn_track_is_data_done(t))
1971 	break;
1972 		}
1973 
1974 		/* update current progress */
1975 		d->progress.sector++;
1976 	}
1977 
1978 	/* (tail padding is done in sector_data()) */
1979 
1980 	/* Pad up buffer to next full o->obs (usually 32 kB) */
1981 	if (o->obs_pad && out->bytes > 0 && out->bytes < o->obs) {
1982 		memset(out->data + out->bytes, 0, o->obs - out->bytes);
1983 		out->sectors += (o->obs - out->bytes) / 2048;
1984 		out->bytes = o->obs;
1985 	}
1986 	ret = burn_write_flush(o, t);
1987 	if (ret <= 0)
1988 		goto ex;
1989 	is_flushed = 1;
1990 
1991 	/* Eventually finalize track */
1992 	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
1993 	    d->current_profile == 0x15) {
1994 		/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
1995 		ret = burn_disc_close_track_dvd_minus_r(o, tnum);
1996 		if (ret <= 0)
1997 			goto ex;
1998 	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
1999 		/* DVD+R , DVD+R/DL */
2000 		ret = burn_disc_close_track_dvd_plus_r(o, tnum,
2001 							 is_last_track);
2002 		if (ret <= 0)
2003 			goto ex;
2004 	} else if (d->current_profile == 0x41) {
2005 		/* BD-R SRM */
2006 		ret = burn_disc_close_track_dvd_plus_r(o, tnum,
2007 							 is_last_track);
2008 		if (ret <= 0)
2009 			goto ex;
2010 	}
2011 	ret = 1;
2012 ex:;
2013 	if (d->cancel)
2014 		burn_source_cancel(t->source);
2015 	if (track_open && !is_flushed)
2016 		d->sync_cache(d); /* burn_write_flush() was not called */
2017 	return ret;
2018 }
2019 
2020 
2021 /* ts A61219 */
burn_disc_close_session_dvd_plus_rw(struct burn_write_opts * o,struct burn_session * s)2022 int burn_disc_close_session_dvd_plus_rw(struct burn_write_opts *o,
2023 					struct burn_session *s)
2024 {
2025 	struct burn_drive *d = o->drive;
2026 
2027 	d->busy = BURN_DRIVE_CLOSING_SESSION;
2028 	/* This seems to be a quick end : "if (!dvd_compat)" */
2029 	/* >>> Stop de-icing (ongoing background format) quickly
2030 	       by mmc_close() (but with opcode[2]=0).
2031 	       Wait for unit to get ready.
2032 	       return 1;
2033 	*/
2034 	/* Else: end eventual background format in a "DVD-RO" compatible way */
2035 	d->close_track_session(d, 1, 0); /* same as CLOSE SESSION for CD */
2036 	d->busy = BURN_DRIVE_WRITING;
2037 	return 1;
2038 }
2039 
2040 
2041 /* ts A61228 */
burn_disc_close_session_dvd_minus_rw(struct burn_write_opts * o,struct burn_session * s)2042 int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o,
2043 					struct burn_session *s)
2044 {
2045 	struct burn_drive *d = o->drive;
2046 
2047 	d->busy = BURN_DRIVE_CLOSING_SESSION;
2048 	if (d->current_profile == 0x13) {
2049 		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
2050 
2051 		/* ??? under what circumstances to use close functiom 011b
2052 		       "Finalize disc" ? */
2053 
2054 	}
2055 	d->busy = BURN_DRIVE_WRITING;
2056 	return 1;
2057 }
2058 
2059 
2060 /* ts A70129 : for profile 0x11 DVD-R, 0x14 DVD-RW Seq, 0x15 DVD-R/DL Seq */
burn_disc_close_session_dvd_minus_r(struct burn_write_opts * o)2061 int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o)
2062 {
2063 	struct burn_drive *d = o->drive;
2064 
2065 	/* only for Incremental writing */
2066 	if (o->write_type != BURN_WRITE_TAO)
2067 		return 2;
2068 
2069 #ifdef Libburn_dvd_r_dl_multi_no_close_sessioN
2070 	if (d->current_profile == 0x15 && o->multi)
2071 		return 2;
2072 #endif
2073 
2074 	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
2075 			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
2076 			"Closing session", 0, 0);
2077 
2078 	d->busy = BURN_DRIVE_CLOSING_SESSION;
2079 	d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
2080 	d->busy = BURN_DRIVE_WRITING;
2081 	return 1;
2082 }
2083 
2084 
2085 /* ts A61218 */
burn_dvd_write_session(struct burn_write_opts * o,struct burn_session * s,int is_last_session)2086 int burn_dvd_write_session(struct burn_write_opts *o,
2087 				struct burn_session *s, int is_last_session)
2088 {
2089 	int i, ret, multi_mem;
2090         struct burn_drive *d = o->drive;
2091 
2092 	/* ts A90108 */
2093 	if (d->current_profile == 0x41 && d->status == BURN_DISC_APPENDABLE &&
2094 	    d->state_of_last_session == 1) {
2095 		/* last session on BD-R is still open */;
2096 
2097 		/* BR-R were not closed by libburn-0.6.0.pl00 if o->multi==0.
2098 		   This leads to an unreadable, but recoverable) media state.
2099 		   Technically they are appendable although the last session
2100 		   is not readable.
2101 
2102 		   By default the open session gets closed here before the new
2103 		   session is written. E.g. after writing a small dummy session
2104 		   number 2 one can read session 1 and write session 3 which
2105 		   points to data of session 1.
2106 
2107 		   For the case that no media with 3 sessions is desired it is
2108 		   possible to activate the following coarse single-session
2109 		   closing code:
2110 		   No new session will be written but calling programs will
2111 		   report success. Quite misleading.
2112 		   Activate only if really needed by
2113 		   # define Libburn_bug_A90108_close_disC yes
2114 		*/
2115 
2116 
2117 #ifdef Libburn_bug_A90108_close_disC
2118 
2119 		/* Close open session and media.
2120 		   That was the goal of the failed run which led to the
2121 		   unreadable (but recoverable) media state.
2122 
2123 		   It is not easy to implement a general close function for
2124 		   all media types. Therefore this pseudo write code is under
2125 		   control of #ifdef.
2126 		*/
2127 		libdax_msgs_submit(libdax_messenger, d->global_index,
2128 				0x00020171,
2129 				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2130 				"Closing BD-R with accidentally open session",
2131 				0, 0);
2132  		d->close_track_session(d, 3, 0); /* CLOSE SESSION, 110b */
2133 		d->state_of_last_session = 3; /* mark as complete session */
2134 		d->status = BURN_DISC_FULL;
2135 		sleep(3); /* The caller might need time to arrange itself */
2136 		return 1;
2137 
2138 #else /* Libburn_bug_A90108_close_disC */
2139 
2140 		/* This is the default mode.
2141 		*/
2142 		libdax_msgs_submit(libdax_messenger, d->global_index,
2143 				0x00020170,
2144 				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2145 				"Closing open session before writing new one",
2146 				0, 0);
2147  		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
2148 		d->state_of_last_session = 3; /* mark as complete session */
2149 
2150 #endif /* ! Libburn_bug_A90108_close_disC */
2151 
2152 	}
2153 
2154 	for (i = 0; i < s->tracks; i++) {
2155 		ret = burn_dvd_write_track(o, s, i,
2156 			is_last_session && i == (s->tracks - 1));
2157 		if (ret <= 0)
2158 	break;
2159 	}
2160 	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
2161 	    d->current_profile == 0x15) {
2162 		/* DVD-R , DVD-RW Sequential, DVD-R/DL Sequential */
2163 		/* If feature 21h failed on write 0: do not close session */
2164 		if (d->was_feat21h_failure != 2) {
2165 			multi_mem = o->multi;
2166 			if (!is_last_session)
2167 				o->multi = 1;
2168 			ret = burn_disc_close_session_dvd_minus_r(o);
2169 			o->multi = multi_mem;
2170 			if (ret <= 0)
2171 				return 0;
2172 		}
2173 	} else if (d->current_profile == 0x12 || d->current_profile == 0x43) {
2174 		/* DVD-RAM , BD-RE */
2175 		/* ??? any finalization needed ? */;
2176 	} else if (d->current_profile == 0x13) {
2177 		/* DVD-RW restricted overwrite */
2178 		if (d->needs_close_session) {
2179 			ret = burn_disc_close_session_dvd_minus_rw(o, s);
2180 			if (ret <= 0)
2181 				return 0;
2182 		}
2183 	} else if (d->current_profile == 0x1a) {
2184 		/* DVD+RW */
2185 		if (d->needs_close_session) {
2186 			ret = burn_disc_close_session_dvd_plus_rw(o, s);
2187 			if (ret <= 0)
2188 				return 0;
2189 		}
2190 	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
2191 		/* DVD+R , DVD+R/DL do each track as an own session */;
2192 	} else if (d->current_profile == 0x41) {
2193 		/* BD-R SRM do each track as an own session */;
2194 	}
2195 	return 1;
2196 }
2197 
2198 
2199 /* ts A61218 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
burn_disc_setup_dvd_plus_rw(struct burn_write_opts * o,struct burn_disc * disc)2200 int burn_disc_setup_dvd_plus_rw(struct burn_write_opts *o,
2201 				struct burn_disc *disc)
2202 {
2203 	struct burn_drive *d = o->drive;
2204 	int ret;
2205 
2206 	if (d->bg_format_status==0 || d->bg_format_status==1) {
2207 		d->busy = BURN_DRIVE_FORMATTING;
2208 		/* start or re-start dvd_plus_rw formatting */
2209 		ret = d->format_unit(d, (off_t) 0, 0);
2210 		if (ret <= 0)
2211 			return 0;
2212 		d->busy = BURN_DRIVE_WRITING;
2213 		d->needs_close_session = 1;
2214 	}
2215 
2216 	/* >>> perform OPC if needed */;
2217 
2218 	/* >>> ? what else ? */;
2219 
2220 	return 1;
2221 }
2222 
2223 
2224 /* ts A61228 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
burn_disc_setup_dvd_minus_rw(struct burn_write_opts * o,struct burn_disc * disc)2225 int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o,
2226 				struct burn_disc *disc)
2227 {
2228 	struct burn_drive *d = o->drive;
2229 	char msg[60];
2230 	int ret;
2231 
2232 	d->nwa = 0;
2233 	if (o->start_byte >= 0) {
2234 		d->nwa = o->start_byte / 32768; /* align to 32 kB */
2235 
2236 		sprintf(msg, "Write start address is  %d * 32768", d->nwa);
2237 		libdax_msgs_submit(libdax_messenger, d->global_index,
2238 				0x00020127,
2239 				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2240 				msg, 0, 0);
2241 
2242 		d->nwa *= 16; /* convert to 2048 block units */
2243 	}
2244 
2245 
2246 	/* ??? mmc5r03c.pdf 7.5.2 :
2247 	"For DVD-RW media ... If a medium is in Restricted overwrite
2248 	 mode, this mode page shall not be used."
2249 
2250 	But growisofs composes a page 5 and sends it.
2251 	mmc5r03c.pdf 5.3.16 , table 127 specifies that mode page 5
2252 	shall be supported with feature 0026h Restricted Overwrite.
2253 	5.3.22 describes a feature 002Ch Rigid Restrictive Overwrite
2254 	which seems to apply to DVD-RW and does not mention page 5.
2255 
2256 	5.4.14 finally states that profile 0013h includes feature
2257 	002Ch rather than 0026h.
2258 
2259 		d->send_write_parameters(d, NULL, -1, o);
2260 	*/
2261 
2262 	d->busy = BURN_DRIVE_FORMATTING;
2263 
2264 	/* "quick grow" to at least byte equivalent of d->nwa */
2265 	ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048,
2266 			     (d->nwa > 0) << 3);
2267 	if (ret <= 0)
2268 		return 0;
2269 
2270 	d->busy = BURN_DRIVE_WRITING;
2271 
2272 	/* >>> perform OPC if needed */;
2273 
2274 	return 1;
2275 }
2276 
2277 
2278 /* ts A70129 : for DVD-R[W] Sequential Recoding */
burn_disc_setup_dvd_minus_r(struct burn_write_opts * o,struct burn_disc * disc)2279 int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o,
2280 				struct burn_disc *disc)
2281 {
2282 	struct burn_drive *d = o->drive;
2283 
2284 	/* most setup is in burn_disc_setup_track_dvd_minus_r() */;
2285 
2286 	d->nwa = 0;
2287 	return 1;
2288 }
2289 
2290 
2291 /* ts A70226 : for DVD+R , DVD+R/DL */
burn_disc_setup_dvd_plus_r(struct burn_write_opts * o,struct burn_disc * disc)2292 int burn_disc_setup_dvd_plus_r(struct burn_write_opts *o,
2293 				struct burn_disc *disc)
2294 {
2295 	struct burn_drive *d = o->drive;
2296 
2297 	/* most setup is in burn_disc_setup_track_dvd_plus_r() */;
2298 
2299 	d->nwa = 0;
2300 	return 1;
2301 }
2302 
2303 
2304 /* ts A61218 - A70415 */
burn_dvd_write_sync(struct burn_write_opts * o,struct burn_disc * disc)2305 int burn_dvd_write_sync(struct burn_write_opts *o,
2306 				 struct burn_disc *disc)
2307 {
2308 	int i, ret, o_end;
2309 	off_t default_size = 0;
2310 	struct burn_drive *d = o->drive;
2311 	struct burn_track *t;
2312 	char *msg = NULL;
2313 
2314 	BURN_ALLOC_MEM(msg, char, 160);
2315 	d->needs_close_session = 0;
2316 
2317 	/* buffer flush trigger for sector.c:get_sector() */
2318 	o->obs = Libburn_dvd_obS;
2319 
2320 	if (d->current_profile == 0x1a || d->current_profile == 0x12 ||
2321 	    d->current_profile == 0x43) {
2322 		/* DVD+RW , DVD-RAM , BD-RE */
2323 		ret = 1;
2324 		if (d->current_profile == 0x1a)
2325 			ret = burn_disc_setup_dvd_plus_rw(o, disc);
2326 		if (ret <= 0) {
2327 			sprintf(msg,
2328 			  "Write preparation setup failed for DVD+RW");
2329 			libdax_msgs_submit(libdax_messenger, d->global_index,
2330 				0x00020121,
2331 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2332 				msg, 0, 0);
2333 			goto early_failure;
2334 		}
2335 		d->nwa = 0;
2336 		if (o->start_byte >= 0) {
2337 			d->nwa = o->start_byte / 2048;
2338 			sprintf(msg, "Write start address is  %d * 2048",
2339 				d->nwa);
2340 			libdax_msgs_submit(libdax_messenger, d->global_index,
2341 				0x00020127,
2342 				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2343 				msg, 0, 0);
2344 		}
2345 		if (o->obs_pad < 2)
2346 			o->obs_pad = 0; /* no filling-up of last 32k buffer */
2347 		if (d->current_profile == 0x43) /* BD-RE */
2348 			o->obs = Libburn_bd_re_obS;
2349 		if (d->do_stream_recording) {
2350 			if (o->obs_pad < 2)
2351 				o->obs_pad = 1;
2352 			if (d->current_profile == 0x43) /* BD-RE */
2353 				o->obs = Libburn_bd_streamed_obS;
2354 		}
2355 
2356 	} else if (d->current_profile == 0x13) {
2357 		 /* DVD-RW Restricted Overwrite */
2358 		ret = burn_disc_setup_dvd_minus_rw(o, disc);
2359 		if (ret <= 0) {
2360 			sprintf(msg,
2361 			  "Write preparation setup failed for DVD-RW");
2362 			libdax_msgs_submit(libdax_messenger, d->global_index,
2363 				0x00020121,
2364 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2365 				msg, 0, 0);
2366 			goto early_failure;
2367 		}
2368 
2369 		/* _Rigid_ Restricted Overwrite demands this */
2370 		o->obs_pad = 1; /* fill-up track's last 32k buffer */
2371 
2372 	} else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
2373 			d->current_profile == 0x15) {
2374 		/* DVD-R , DVD-RW Sequential , DVD-R/DL Sequential */
2375 		t = disc->session[0]->track[0];
2376 		o_end = ( burn_track_is_open_ended(t) && !o->fill_up_media );
2377 		default_size = burn_track_get_default_size(t);
2378 		if (o->write_type == BURN_WRITE_SAO && o_end) {
2379 			sprintf(msg, "Activated track default size %.f",
2380 				(double) default_size);
2381 			libdax_msgs_submit(libdax_messenger,
2382 				  d->global_index, 0x0002012e,
2383 				  LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2384 				  msg, 0, 0);
2385 			burn_track_set_size(t, default_size);
2386 		}
2387 		/* Whether to fill-up last 32k buffer of track. */
2388 		if (o->obs_pad < 2)
2389 			o->obs_pad = (o->write_type != BURN_WRITE_SAO);
2390 		ret = burn_disc_setup_dvd_minus_r(o, disc);
2391 		if (ret <= 0) {
2392 			sprintf(msg,
2393 			  "Write preparation setup failed for DVD-R[W]");
2394 			libdax_msgs_submit(libdax_messenger, d->global_index,
2395 				0x00020121,
2396 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2397 				msg, 0, 0);
2398 			goto early_failure;
2399 		}
2400 
2401 	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b ||
2402 		   d->current_profile == 0x41) {
2403 		/* DVD+R , DVD+R/DL , BD-R SRM */
2404 
2405 		/* >>> ts A81208 : with BD-R set o->obs to 64 kB ? */
2406 
2407 		t = disc->session[0]->track[0];
2408 		o_end = ( burn_track_is_open_ended(t) && !o->fill_up_media );
2409 		default_size = burn_track_get_default_size(t);
2410 		if (o->write_type == BURN_WRITE_SAO && o_end) {
2411 			sprintf(msg, "Activated track default size %.f",
2412 				(double) default_size);
2413 			libdax_msgs_submit(libdax_messenger,
2414 				  d->global_index, 0x0002012e,
2415 				  LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
2416 				  msg, 0, 0);
2417 			burn_track_set_size(t, default_size);
2418 		}
2419 		ret = burn_disc_setup_dvd_plus_r(o, disc);
2420 		if (ret <= 0) {
2421 			sprintf(msg, "Write preparation setup failed for %s",
2422 			   	d->current_profile == 0x41 ? "BD-R" : "DVD+R");
2423 			libdax_msgs_submit(libdax_messenger, d->global_index,
2424 				0x00020121,
2425 				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2426 				msg, 0, 0);
2427 			goto early_failure;
2428 		}
2429 		/* ??? padding needed ??? cowardly doing it for now */
2430 		if (o->obs_pad < 2)
2431 			o->obs_pad = 1; /* fill-up track's last obs buffer */
2432 		if (d->current_profile == 0x41) /* BD-R */
2433 			o->obs = Libburn_bd_r_obS;
2434 		if (d->do_stream_recording) {
2435 			if (d->current_profile == 0x41) /* BD-R */
2436 				o->obs = Libburn_bd_streamed_obS;
2437 		}
2438 	}
2439 
2440 #ifdef Libburn_dvd_obs_default_64K
2441 	o->obs = 64 * 1024;
2442 #endif
2443 
2444 	/* <<< test only : Does this increase effective speed with USB ?
2445 		ts A90801 : 64kB: speed with 16x DVD-R is 12 rather than 8
2446 		            128kB: glibc complains about double free
2447 		                   With BURN_OS_TRANSPORT_BUFFER_SIZE
2448 		                   enlarged to 128 MB, the first WRITE fails
2449 		                   with an i/o error.
2450 	o->obs = 64 * 1024;
2451 	*/
2452 
2453 	if (o->dvd_obs_override >= 32 * 1024)
2454 		o->obs = o->dvd_obs_override;
2455 
2456 	if (o->obs > BUFFER_SIZE) {
2457 		sprintf(msg, "Chosen write chunk size %d exceeds system dependent buffer size", o->obs);
2458 		libdax_msgs_submit(libdax_messenger, d->global_index,
2459 				 0x00000002, LIBDAX_MSGS_SEV_DEBUG,
2460 				 LIBDAX_MSGS_PRIO_ZERO, msg, 0, 0);
2461 		o->obs = 32 * 1024; /* This size is required to work */
2462 	}
2463 
2464 	if (d->do_stream_recording &&
2465 		(d->current_profile == 0x43 || d->current_profile == 0x41) &&
2466 		o->obs < Libburn_bd_streamed_obS) {
2467 		/* LG GGW-H20 writes junk with stream recording and obs=32k */
2468 		sprintf(msg,
2469 		   "Stream recording disabled because of small output buffer");
2470 		libdax_msgs_submit(libdax_messenger, d->global_index,
2471 			 0x00020176, LIBDAX_MSGS_SEV_NOTE,
2472 			 LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
2473 		d->do_stream_recording = 0;
2474 	}
2475 
2476 	sprintf(msg, "dvd/bd Profile= %2.2Xh , obs= %d , obs_pad= %d",
2477 		d->current_profile, o->obs, o->obs_pad);
2478 	libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
2479 		LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg, 0, 0);
2480 
2481 	for (i = 0; i < disc->sessions; i++) {
2482 		/* update progress */
2483 		d->progress.session = i;
2484 		d->progress.tracks = disc->session[i]->tracks;
2485 
2486 		ret = burn_dvd_write_session(o, disc->session[i],
2487 					i == (disc->sessions - 1));
2488 		if (ret <= 0)
2489 			goto ex;
2490 
2491 		/* XXX: currently signs an end of session */
2492 		d->progress.sector = 0;
2493 		d->progress.start_sector = 0;
2494 		d->progress.sectors = 0;
2495 	}
2496 	ret = 1;
2497 ex:;
2498 
2499 	/* >>> eventual emergency finalization measures */
2500 
2501 	/* update media state records */
2502 	burn_drive_mark_unready(d, 0);
2503 	burn_drive_inquire_media(d);
2504 
2505 	if (d->current_profile == 0x41 && d->complete_sessions >= 300) {
2506 		sprintf(msg, "Sequential BD-R media now contains %d sessions. It is likely to soon fail writing.", d->complete_sessions);
2507 		libdax_msgs_submit(libdax_messenger, d->global_index,
2508 				0x0002017b, LIBDAX_MSGS_SEV_WARNING,
2509 				LIBDAX_MSGS_PRIO_ZERO, msg, 0, 0);
2510 	}
2511 	BURN_FREE_MEM(msg);
2512 	return ret;
2513 early_failure:;
2514 	BURN_FREE_MEM(msg);
2515 	return 0;
2516 }
2517 
2518 
2519 /* ts A70904 */
burn_stdio_open_write(struct burn_drive * d,off_t start_byte,int sector_size,int flag)2520 int burn_stdio_open_write(struct burn_drive *d, off_t start_byte,
2521 			 int sector_size, int flag)
2522 {
2523 
2524 /* We normally need _LARGEFILE64_SOURCE defined by the build system.
2525    Nevertheless the system might use large address integers by default.
2526 */
2527 #ifndef O_LARGEFILE
2528 #define O_LARGEFILE 0
2529 #endif
2530 
2531 	int fd = -1;
2532 	int mode = O_RDWR | O_CREAT | O_LARGEFILE;
2533 	char msg[60];
2534 	off_t lseek_res;
2535 
2536 	if(d->drive_role == 4) {
2537 		libdax_msgs_submit(libdax_messenger, d->global_index,
2538 			0x00020181,
2539 			LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2540 			"Pseudo-drive is a read-only file. Cannot write.",
2541 			0, 0);
2542 		return 0;
2543 	}
2544 	if (d->drive_role == 5 || d->drive_role == 3)
2545 		mode = O_WRONLY | O_CREAT | O_LARGEFILE;
2546 	if (d->devname[0] == 0) /* null drives should not come here */
2547 		return -1;
2548 	fd = burn_drive__fd_from_special_adr(d->devname);
2549 	if (fd >= 0)
2550 		fd = dup(fd); /* check validity and make closeable */
2551 	else
2552 		fd = open(d->devname, mode | O_BINARY,
2553                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
2554 	if (fd == -1) {
2555 		libdax_msgs_submit(libdax_messenger, d->global_index,
2556 			0x00020005,
2557 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2558 			"Failed to open device (a pseudo-drive)", errno, 0);
2559 		d->cancel = 1;
2560 		return -1;
2561 	}
2562 	if (start_byte < 0)
2563 		start_byte = 0;
2564 	if (d->drive_role == 2 || d->drive_role == 5) {
2565 		lseek_res = lseek(fd, start_byte, SEEK_SET);
2566 		if (lseek_res == -1) {
2567 			sprintf(msg, "Cannot address start byte %.f",
2568 				(double) start_byte);
2569 			libdax_msgs_submit(libdax_messenger, d->global_index,
2570 				0x00020147,
2571 				LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2572 				msg, errno, 0);
2573 			close(fd);
2574 			d->cancel = 1;
2575 			fd = -1;
2576 		}
2577 	}
2578 	d->nwa = start_byte / sector_size;
2579 	return fd;
2580 }
2581 
2582 
2583 /* ts A70904 */
burn_stdio_read_source(struct burn_source * source,char * buf,int bufsize,struct burn_write_opts * o,int flag)2584 int burn_stdio_read_source(struct burn_source *source, char *buf, int bufsize,
2585 			 	struct burn_write_opts *o, int flag)
2586 {
2587 	int count= 0, todo;
2588 
2589 	for(todo = bufsize; todo > 0; todo -= count) {
2590 		if(source->read!=NULL)
2591 			count = source->read(source,
2592 			    (unsigned char *) (buf + (bufsize - todo)), todo);
2593 		else
2594 			count = source->read_xt(source,
2595 			    (unsigned char *) (buf + (bufsize - todo)), todo);
2596 		if (count <= 0)
2597 	break;
2598 	}
2599 	return (bufsize - todo);
2600 }
2601 
2602 
2603 /* ts A70904 */
burn_stdio_write(int fd,char * buf,int count,struct burn_drive * d,int flag)2604 int burn_stdio_write(int fd, char *buf, int count, struct burn_drive *d,
2605 			 int flag)
2606 {
2607 	int ret = 0;
2608 	char *msg = NULL;
2609 	int todo, done, retries;
2610 
2611 	if (d->cancel || count <= 0)
2612 		return 0;
2613 	if(d->do_simulate)
2614 		return 1;
2615 
2616 	todo = count;
2617 	done = 0;
2618 	for (retries = 0; todo > 0 && retries <= Libburn_stdio_write_retrieS;
2619              retries++) {
2620 /*
2621 fprintf(stderr, "libburn_DEBUG: write(%d, %lX, %d)\n",
2622                 fd, (unsigned long) buf, count);
2623 */
2624 		ret = write(fd, buf + done, todo);
2625 		if (ret < 0)
2626 	break;
2627 		done += ret;
2628 		todo -= ret;
2629 	}
2630 	if (done != count) {
2631 		BURN_ALLOC_MEM(msg, char, 160);
2632 
2633 		sprintf(msg, "Cannot write desired amount of %d bytes.", count);
2634 		if (retries > 1)
2635 			sprintf(msg + strlen(msg), " Did %d retries. Last",
2636 			        retries - 1);
2637 		sprintf(msg + strlen(msg), " write(2) returned %d.", ret);
2638 		libdax_msgs_submit(libdax_messenger, d->global_index,
2639 			0x00020148,
2640 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2641 			msg, errno, 0);
2642 		d->cancel = 1;
2643 		ret = 0; goto ex;
2644 	}
2645 	ret = 1;
2646 ex:;
2647 	BURN_FREE_MEM(msg);
2648 	return ret;
2649 }
2650 
2651 
2652 /* ts A70910 : to be used as burn_drive.write(), emulating mmc_write() */
burn_stdio_mmc_write(struct burn_drive * d,int start,struct buffer * buf)2653 int burn_stdio_mmc_write(struct burn_drive *d, int start, struct buffer *buf)
2654 {
2655 	int ret;
2656 	off_t start_byte;
2657 
2658 	if (d->cancel)
2659 		return BE_CANCELLED;
2660 	if (d->stdio_fd < 0) {
2661 		libdax_msgs_submit(libdax_messenger, d->global_index,
2662 			0x0002017d,
2663 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2664 			"Invalid file descriptor with stdio pseudo-drive",
2665 			0, 0);
2666 		d->cancel = 1;
2667 		return BE_CANCELLED;
2668 	}
2669 	if (start != d->nwa) {
2670 		char msg[80];
2671 
2672 		start_byte = ((off_t) start) *
2673 				(off_t) (buf->bytes / buf->sectors);
2674 		if (lseek(d->stdio_fd, start_byte, SEEK_SET)==-1) {
2675 			sprintf(msg, "Cannot address start byte %.f",
2676 			 	(double) start_byte);
2677 			libdax_msgs_submit(libdax_messenger, d->global_index,
2678 				0x00020147,
2679 				LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2680 				msg, errno, 0);
2681 			d->cancel = 1;
2682 			return BE_CANCELLED;
2683 		}
2684 		d->nwa = start;
2685 	}
2686 	ret = burn_stdio_write(d->stdio_fd,(char *)buf->data, buf->bytes, d,0);
2687 	if (ret <= 0)
2688 		return BE_CANCELLED;
2689 	d->nwa += buf->sectors;
2690 	return 0;
2691 }
2692 
2693 
2694 /* ts A70910 : to be used as burn_drive.write(),
2695                emulating mmc_write() with simulated writing. */
burn_stdio_mmc_dummy_write(struct burn_drive * d,int start,struct buffer * buf)2696 int burn_stdio_mmc_dummy_write(struct burn_drive *d, int start,
2697 							struct buffer *buf)
2698 {
2699 	if (d->cancel)
2700 		return BE_CANCELLED;
2701 	d->nwa = start + buf->sectors;
2702 	return 0;
2703 }
2704 
2705 
2706 /* ts A70911 */
2707 /* Flush stdio system buffer to physical device.
2708    @param flag bit0= do not report debug message (intermediate sync)
2709                bit1= do fsync(2) unconditionally
2710 */
burn_stdio_sync_cache(int fd,struct burn_drive * d,int flag)2711 int burn_stdio_sync_cache(int fd, struct burn_drive *d, int flag)
2712 {
2713 	int ret, do_fsync;
2714 	char *msg = NULL;
2715 
2716 	if (fd < 0) {
2717 		libdax_msgs_submit(libdax_messenger, d->global_index,
2718 			0x0002017d,
2719 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
2720 			"Invalid file descriptor with stdio pseudo-drive",
2721 			0, 0);
2722 		d->cancel = 1;
2723 		ret = 0; goto ex;
2724 	}
2725 	d->needs_sync_cache = 0;
2726 	do_fsync = 0;
2727 	if (flag & 2)
2728 		do_fsync = 1;
2729 	else if (d->write_opts != NULL)
2730 		do_fsync = (d->write_opts->stdio_fsync_size >= 0);
2731 	if (do_fsync) {
2732 		if (!(flag & 1))
2733 			libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
2734 				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
2735 				"syncing cache (stdio fsync)", 0, 0);
2736 		ret = fsync(fd);
2737 	} else {
2738 		ret = 0;
2739 	}
2740 	if (ret != 0 && errno == EIO) {
2741 		BURN_ALLOC_MEM(msg, char, 160);
2742 
2743 		sprintf(msg,
2744 		  "Cannot write desired amount of data. fsync(2) returned %d.",
2745 		  ret);
2746 		libdax_msgs_submit(libdax_messenger, d->global_index,
2747 			0x00020148,
2748 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2749 			msg, errno, 0);
2750 		d->cancel = 1;
2751 		ret = 0; goto ex;
2752 	}
2753 	ret = 1;
2754 ex:;
2755 	BURN_FREE_MEM(msg);
2756 	return ret;
2757 }
2758 
2759 
2760 /* ts A70911 : to be used as burn_drive.sync_cache(),
2761                emulating mmc_sync_cache() */
burn_stdio_mmc_sync_cache(struct burn_drive * d)2762 void burn_stdio_mmc_sync_cache(struct burn_drive *d)
2763 {
2764 	burn_stdio_sync_cache(d->stdio_fd, d, 0);
2765 }
2766 
2767 
2768 /* ts C00824 : API */
2769 /* Enforces nominal write speed */
burn_nominal_slowdown(int kb_per_second,int max_corr,struct timeval * prev_time,int * us_corr,off_t b_since_prev,int flag)2770 int burn_nominal_slowdown(int kb_per_second, int max_corr,
2771 			  struct timeval *prev_time,
2772 			  int *us_corr, off_t b_since_prev, int flag)
2773 {
2774 	struct timeval tnow;
2775 	double to_wait, goal, corr;
2776 	int abs_max_corr;
2777 
2778 	if (flag & 1) {
2779 		gettimeofday(prev_time, NULL);
2780 		*us_corr = 0;
2781 		return 1;
2782 	}
2783 	if (kb_per_second <= 0)
2784 		return 2;
2785 
2786 	if (max_corr < -1.0e9 || max_corr > 1.0e9)
2787 		abs_max_corr = 1000000000;
2788 	else
2789 		abs_max_corr = abs(max_corr);
2790 	gettimeofday(&tnow, NULL);
2791 	goal = ((double) b_since_prev) / 1000.0 / ((double) kb_per_second) +
2792 		((double) prev_time->tv_sec) +
2793 		((double) prev_time->tv_usec) / 1.0e6 +
2794 		((double) *us_corr) / 1.0e6 ;
2795 	to_wait = goal - ((double) tnow.tv_sec) -
2796 		  ((double) tnow.tv_usec) / 1.0e6;
2797 
2798 	/* usleep might be restricted to 999999 microseconds */
2799 	while (to_wait > 0.0) {
2800 		if (to_wait >= 0.5) {
2801 			usleep(500000);
2802 			to_wait -= 0.5;
2803 		} else if (to_wait >= 0.00001) {
2804 			usleep((int) (to_wait * 1000000.0));
2805 			to_wait = 0.0;
2806 		} else {
2807 			to_wait = 0.0;
2808 		}
2809 	}
2810 	gettimeofday(prev_time, NULL);
2811 	corr = (goal - ((double) prev_time->tv_sec) -
2812 		((double) prev_time->tv_usec) / 1.0e6) * 1.0e6;
2813 	if (corr > abs_max_corr)
2814 		*us_corr = abs_max_corr;
2815 	else if (corr < -abs_max_corr)
2816 		*us_corr = -abs_max_corr;
2817 	else
2818 		*us_corr = corr;
2819 	return 1;
2820 }
2821 
2822 
2823 /* ts A70904 */
burn_stdio_write_track(struct burn_write_opts * o,struct burn_session * s,int tnum,int flag)2824 int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s,
2825 				int tnum, int flag)
2826 {
2827 	int open_ended, bufsize = 16 * 2048, ret, sectors;
2828 	struct burn_track *t = s->track[tnum];
2829 	struct burn_drive *d = o->drive;
2830 	char *buf = NULL;
2831 	int i, prev_sync_sector = 0, us_corr = 0, max_corr = 250000;
2832 	struct buffer *out = d->buffer;
2833 	struct timeval prev_time;
2834 
2835 	BURN_ALLOC_MEM(buf, char, bufsize);
2836 
2837 	sectors = burn_track_get_sectors_2(t, 1);
2838 	burn_disc_init_track_status(o, s, t, tnum, sectors);
2839 	open_ended = burn_track_is_open_ended(t);
2840 
2841 	t->end_on_premature_eoi = (o->write_type == BURN_WRITE_TAO);
2842 
2843 	/* attach stdio emulators for mmc_*() functions */
2844 	if (o->simulate)
2845 		d->write = burn_stdio_mmc_dummy_write;
2846 	else
2847 		d->write = burn_stdio_mmc_write;
2848 	d->do_simulate = o->simulate;
2849 	d->sync_cache = burn_stdio_mmc_sync_cache;
2850 
2851 	/* initialize */
2852 	burn_nominal_slowdown(d->nominal_write_speed, max_corr,
2853 				&prev_time, &us_corr, (off_t) 0, 1);
2854 
2855 	for (i = 0; open_ended || i < sectors; i++) {
2856 		/* transact a (CD sized) sector */
2857 		if (!sector_data(o, t, 0))
2858 			{ret= 0; goto ex;}
2859 		if (open_ended)
2860 			d->progress.sectors = sectors = d->progress.sector;
2861 		if (open_ended || t->end_on_premature_eoi) {
2862 			if (burn_track_is_data_done(t))
2863 	break;
2864 		}
2865 		d->progress.sector++;
2866 		/* Flush to disk from time to time */
2867 		if (o->stdio_fsync_size > 0) {
2868 			if (d->progress.sector - prev_sync_sector >=
2869 			    o->stdio_fsync_size) {
2870 				if (!o->simulate)
2871 					burn_stdio_sync_cache(d->stdio_fd, d,
2872 									 1);
2873 				burn_nominal_slowdown(
2874 					d->nominal_write_speed, max_corr,
2875 					&prev_time, &us_corr,
2876 					(off_t) (d->progress.sector -
2877 						 prev_sync_sector) *
2878 						 (off_t) 2048,
2879 					0);
2880 				prev_sync_sector = d->progress.sector;
2881 			}
2882 		} else if ((d->progress.sector % 512) == 0) {
2883 			burn_nominal_slowdown(d->nominal_write_speed, max_corr,
2884 				&prev_time, &us_corr, (off_t) (512 * 2048), 0);
2885 		}
2886 	}
2887 
2888 	/* Pad up buffer to next full o->obs (usually 32 kB) */
2889 	if (o->obs_pad && out->bytes > 0 && out->bytes < o->obs) {
2890 		memset(out->data + out->bytes, 0, o->obs - out->bytes);
2891 		out->sectors += (o->obs - out->bytes) / 2048;
2892 		out->bytes = o->obs;
2893 	}
2894 	ret = burn_write_flush(o, t);
2895 	ret= 1;
2896 ex:;
2897 	if (d->cancel)
2898 		burn_source_cancel(t->source);
2899 	if (t->end_on_premature_eoi == 2)
2900 		d->cancel = 1;
2901 	BURN_FREE_MEM(buf);
2902 	return ret;
2903 }
2904 
2905 
2906 /* ts A70904 */
burn_stdio_write_sync(struct burn_write_opts * o,struct burn_disc * disc)2907 int burn_stdio_write_sync(struct burn_write_opts *o,
2908 				 struct burn_disc *disc)
2909 {
2910 	int ret;
2911 	struct burn_drive *d = o->drive;
2912 
2913 	d->needs_close_session = 0;
2914 	if (o->obs_pad < 2)
2915 		o->obs_pad = 0; /* no filling-up of track's last 32k buffer */
2916 	o->obs = 32*1024; /* buffer size */
2917 
2918 	if (disc->sessions != 1)
2919 		{ret= 0 ; goto ex;}
2920 	if (disc->session[0]->tracks != 1)
2921 		{ret= 0 ; goto ex;}
2922 
2923 	/* update progress */
2924 	d->progress.session = 0;
2925 	d->progress.tracks = 1;
2926 
2927 	/* >>> adjust sector size (2048) to eventual audio or even raw */
2928 
2929 	/* >>> ??? ts B11004 : Why this eagerness to close and open ? */
2930 
2931 	/* open target file */
2932 	if (d->stdio_fd >= 0)
2933 		close(d->stdio_fd);
2934 	if (d->drive_role == 5 && d->status == BURN_DISC_APPENDABLE &&
2935             o->start_byte < 0)
2936 		o->start_byte = d->role_5_nwa * 2048;
2937 	d->stdio_fd = burn_stdio_open_write(d, o->start_byte, 2048, 0);
2938 	if (d->stdio_fd == -1)
2939 		{ret = 0; goto ex;}
2940 
2941 	ret = burn_stdio_write_track(o, disc->session[0], 0, 0);
2942 	if (ret <= 0)
2943 		goto ex;
2944 
2945 	/* XXX: currently signs an end of session */
2946 	d->progress.sector = 0;
2947 	d->progress.start_sector = 0;
2948 	d->progress.sectors = 0;
2949 	ret = 1;
2950 ex:;
2951 
2952 	/* >>> ??? ts B11004 : Why this eagerness to close ? */
2953 
2954 	if (d->stdio_fd >= 0)
2955 		close(d->stdio_fd);
2956 	d->stdio_fd = -1;
2957 
2958 	/* update pseudo-media state records by re-grabbing */
2959 	burn_drive_mark_unready(d, 8);
2960 	burn_drive_grab_stdio(d, 1);
2961 
2962 	return ret;
2963 }
2964 
2965 
burn_disc_write_sync(struct burn_write_opts * o,struct burn_disc * disc)2966 void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
2967 {
2968 	struct cue_sheet *sheet;
2969 	struct burn_drive *d = o->drive;
2970 	struct buffer *buffer_mem = o->drive->buffer;
2971 	struct burn_session *s;
2972 	struct burn_track *lt, *t;
2973 	int first = 1, i, ret, lba, nwa = 0, multi_mem, stream_recording_start;
2974 	off_t default_size;
2975 	char msg[80];
2976 
2977 
2978 /* ts A60924 : libburn/message.c gets obsoleted
2979 	burn_message_clear_queue();
2980 */
2981 
2982 	/* ts A61224 */
2983 	burn_disc_init_write_status(o, disc); /* must be done very early */
2984 
2985 	/* ts A80412 , A90227 , B90411 */
2986 	if (o->do_stream_recording >= 16)
2987 		stream_recording_start = o->do_stream_recording;
2988 	else
2989 		stream_recording_start = 0;
2990 	burn_drive_set_stream_recording(d, !!o->do_stream_recording,
2991 					stream_recording_start, 0);
2992 
2993 	/* ts A91122 : Get buffer suitable for sources made by
2994 	               burn_os_open_track_src() */
2995 	d->buffer = burn_os_alloc_buffer(sizeof(struct buffer), 0);
2996 	if (d->buffer == NULL)
2997 		goto fail_wo_sync;
2998 
2999 /* >>> ts A90321
3000 
3001 	memset(d->buffer, 0, sizeof(struct buffer));
3002 
3003 fprintf(stderr, "libburn_DEBUG: d->buffer = %lX , size = %d\n",
3004                 (unsigned long) d->buffer, (int) sizeof(struct buffer));
3005 
3006 calloc() seems not to have the desired effect. valgrind warns:
3007 ==18251== Syscall param write(buf) points to uninitialised byte(s)
3008 ==18251==    at 0x5071DEB: (within /lib64/libpthread-2.5.so)
3009 ==18251==    by 0x4723FA: burn_stdio_write (write.c:1850)
3010 ==18251==    by 0x4725DC: burn_stdio_mmc_write (write.c:1894)
3011 ==18251==    by 0x483B7A: get_sector (sector.c:229)
3012 ==18251==    by 0x484F11: sector_data (sector.c:639)
3013 ==18251==    by 0x4729FE: burn_stdio_write_track (write.c:2012)
3014 ==18251==    by 0x472CF4: burn_stdio_write_sync (write.c:2072)
3015 ==18251==    by 0x472E8D: burn_disc_write_sync (write.c:2125) <<< we are here
3016 ==18251==    by 0x460254: write_disc_worker_func (async.c:514)
3017 ==18251==    by 0x506B09D: start_thread (in /lib64/libpthread-2.5.so)
3018 ==18251==    by 0x55484CC: clone (in /lib64/libc-2.5.so)
3019 */
3020 
3021 	d->rlba = -150;
3022 	d->toc_temp = 9;
3023 
3024 	if(d->drive_role == 4) {
3025 		libdax_msgs_submit(libdax_messenger, d->global_index,
3026 			0x00020181,
3027 			LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
3028 			"Pseudo-drive is a read-only file. Cannot write.",
3029 			0, 0);
3030 		goto fail_wo_sync;
3031 	}
3032 	/* ts A70904 */
3033 	if (d->drive_role != 1) {
3034 		ret = burn_stdio_write_sync(o, disc);
3035 		if (ret <= 0)
3036 			goto fail_wo_sync;
3037 		goto ex;
3038 	}
3039 	/* ts A61218 */
3040 	if (! d->current_is_cd_profile) {
3041 		ret = burn_dvd_write_sync(o, disc);
3042 		if (ret <= 0)
3043 			goto fail_wo_sync;
3044 		goto ex;
3045 	}
3046 
3047 	/* ts A70521 : GNU/Linux 2.4 USB audio fails with 64 kiB */
3048 	/* ts A80414 : might need 64 kiB for BD-RE streaming */
3049         /* buffer flush trigger for sector.c:get_sector() */
3050 	o->obs = Libburn_cd_obS;
3051 
3052 	sprintf(msg, "cd Profile= %2.2Xh , obs= %d , obs_pad= %d",
3053 		d->current_profile, o->obs, o->obs_pad);
3054 	libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
3055 		LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg, 0, 0);
3056 
3057 	/* ts A70218 */
3058 	if (o->write_type == BURN_WRITE_SAO) {
3059 		for (i = 0 ; i < disc->session[0]->tracks; i++) {
3060 			t = disc->session[0]->track[i];
3061 			if (burn_track_is_open_ended(t)) {
3062 				default_size = burn_track_get_default_size(t);
3063 				sprintf(msg,
3064 					"Activated track default size %.f",
3065 					(double) default_size);
3066 				libdax_msgs_submit(libdax_messenger,
3067 					d->global_index, 0x0002012e,
3068 					LIBDAX_MSGS_SEV_NOTE,
3069 					LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
3070 				burn_track_set_size(t, default_size);
3071 			}
3072 		}
3073 	}
3074 
3075 /* Apparently some drives require this command to be sent, and a few drives
3076 return crap.  so we send the command, then ignore the result.
3077 */
3078 	/* ts A61107 : moved up send_write_parameters because LG GSA-4082B
3079 			 seems to dislike get_nwa() in advance */
3080 	d->alba = d->start_lba; /* ts A61114: this looks senseless */
3081 	d->nwa = d->alba;
3082 	if (o->write_type == BURN_WRITE_TAO) {
3083 		nwa = 0; /* get_nwa() will be called in burn_track() */
3084 	} else {
3085 		if (disc->sessions > 0)
3086 			s = disc->session[0];
3087 		else
3088 			s = NULL;
3089 		d->send_write_parameters(d, s, -1, o);
3090 
3091 		ret = d->get_nwa(d, -1, &lba, &nwa);
3092 		sprintf(msg,
3093 			"SAO|RAW: Inquired nwa: %d , ret= %d , cap=%.f\n",
3094 			nwa, ret, (double) d->media_capacity_remaining);
3095 		libdax_msgs_submit(libdax_messenger, d->global_index,
3096 				0x00000002,
3097 				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
3098 				msg,0, 0);
3099 
3100 		/* >>> ts A70212 : CD-DAO/SAO : eventually expand size of last track to maximum */;
3101 
3102 	}
3103 
3104 	for (i = 0; i < disc->sessions; i++) {
3105 		/* update progress */
3106 		d->progress.session = i;
3107 		d->progress.tracks = disc->session[i]->tracks;
3108 
3109 		/* ts A61114: added parameter nwa */
3110 		sheet = burn_create_toc_entries(o, disc->session[i], nwa);
3111 
3112 		/* ts A61009 */
3113 		if (sheet == NULL)
3114 			goto fail_wo_sync;
3115 
3116 #ifdef Libburn_write_with_function_print_cuE
3117 		print_cue(sheet);
3118 		/* goto fail_wo_sync; */
3119 #endif /* Libburn_write_with_function_print_cuE */
3120 
3121 		d->medium_state_changed = 1;
3122 		ret = 1;
3123 		if (o->write_type == BURN_WRITE_SAO)
3124 			ret = d->send_cue_sheet(d, sheet);
3125 		if (sheet->data != NULL)
3126 			free(sheet->data);
3127 		free(sheet);
3128 		if (ret <= 0)
3129 			goto fail_wo_sync;
3130 
3131 		/* --- From here on, final sync is needed. --- */
3132 
3133 		if (o->write_type == BURN_WRITE_RAW) {
3134 			if (!burn_write_leadin(o, disc->session[i], first))
3135 				goto fail;
3136 		} else {
3137 			if (first) {
3138 
3139 				/* ts A61030 : 0 made the burner take data. */
3140 				/* ts A61103 : Meanwhile d->nwa is updated in
3141 						burn_write_track()  */
3142 				if(o->write_type == BURN_WRITE_TAO) {
3143 					d->nwa= d->alba = 0;
3144 				} else {
3145 
3146 #ifdef Libburn_sao_can_appenD
3147 					/* ts A61114: address for d->write() */
3148 					if (d->status == BURN_DISC_APPENDABLE
3149 					  && o->write_type == BURN_WRITE_SAO) {
3150 						d->nwa = d->alba = nwa-150;
3151 
3152 						sprintf(msg,
3153 				"SAO appendable d->nwa= %d\n", d->nwa);
3154 						libdax_msgs_submit(
3155 				libdax_messenger, d->global_index, 0x00000002,
3156 				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
3157 				msg, 0, 0);
3158 
3159 					} else {
3160 						d->nwa = -150;
3161 						d->alba = -150;
3162 					}
3163 #else
3164 					d->nwa = -150;
3165 					d->alba = -150;
3166 #endif /* ! Libburn_sao_can_appenD */
3167 
3168 
3169 				}
3170 
3171 			} else {
3172 				d->nwa += 4500;
3173 				d->alba += 4500;
3174 			}
3175 		}
3176 		multi_mem = o->multi;
3177 		if(i < disc->sessions - 1)
3178 			o->multi = 1;
3179 		ret = burn_write_session(o, disc->session[i]);
3180 		o->multi = multi_mem;
3181 		if (!ret)
3182 			goto fail;
3183 
3184 		lt = disc->session[i]->track[disc->session[i]->tracks - 1];
3185 		if (o->write_type == BURN_WRITE_RAW) {
3186 			if (!burn_write_leadout(o, first, lt->entry->control,
3187 			                        lt->mode))
3188 				goto fail;
3189 		} else {
3190 
3191 			/* ts A61030 */
3192 			if (o->write_type != BURN_WRITE_TAO)
3193 
3194 				if (!burn_write_flush(o, NULL))
3195 					goto fail;
3196 
3197 			d->nwa += first ? 6750 : 2250;
3198 			d->alba += first ? 6750 : 2250;
3199 		}
3200 		if (first)
3201 			first = 0;
3202 
3203 		/* XXX: currently signs an end of session */
3204 		d->progress.sector = 0;
3205 		d->progress.start_sector = 0;
3206 		d->progress.sectors = 0;
3207 	}
3208 
3209 	/* ts A61030: extended skipping of flush to TAO: session is closed */
3210 	if (o->write_type != BURN_WRITE_SAO && o->write_type != BURN_WRITE_TAO)
3211 		if (!burn_write_flush(o, NULL))
3212 			goto fail;
3213 
3214 	sleep(1);
3215 
3216 	/* ts A61125 : update media state records */
3217 	burn_drive_mark_unready(d, 0);
3218 	burn_drive_inquire_media(d);
3219 
3220 	/* ts A61012 : This return was traditionally missing. I suspect this
3221 			to have caused Cdrskin_eject() failures */
3222 	goto ex;
3223 
3224 fail:
3225 	d->sync_cache(d);
3226 fail_wo_sync:;
3227 	usleep(500001); /* ts A61222: to avoid a warning from remove_worker()*/
3228 	libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010b,
3229 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
3230 			"Burn run failed", 0, 0);
3231 	d->cancel = 1;
3232 	/* <<< d->busy = BURN_DRIVE_IDLE; */
3233 ex:;
3234 	d->do_stream_recording = 0;
3235 	if (d->buffer != NULL)
3236 		burn_os_free_buffer((char *) d->buffer,
3237 					sizeof(struct buffer), 0);
3238 	d->buffer = buffer_mem;
3239 	if (d->write_opts != NULL) {
3240 		burn_write_opts_free(d->write_opts);
3241 		d->write_opts = NULL;
3242 	}
3243 	if (d->write_retry_count > 0) {
3244 		sprintf(msg, "WRITE command repetition happened %u times",
3245 			d->write_retry_count);
3246 		libdax_msgs_submit(libdax_messenger, d->global_index,
3247 			0x000201ad,
3248 			LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
3249 			msg, 0, 0);
3250 	}
3251 	return;
3252 }
3253 
3254 /* ts A70811 : API function */
burn_random_access_write(struct burn_drive * d,off_t byte_address,char * data,off_t data_count,int flag)3255 int burn_random_access_write(struct burn_drive *d, off_t byte_address,
3256 				char *data, off_t data_count, int flag)
3257 {
3258 	int alignment = 0, start, upto, chunksize, err, fd = -1, ret;
3259 	int do_close = 0, getfl_ret;
3260 	char msg[81], *rpt;
3261 	struct buffer *buf = NULL, *buffer_mem = d->buffer;
3262 
3263 	BURN_ALLOC_MEM(buf, struct buffer, 1);
3264 	if (d->released) {
3265 		libdax_msgs_submit(libdax_messenger,
3266 			d->global_index, 0x00020142,
3267 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
3268 			"Drive is not grabbed on random access write", 0, 0);
3269 		{ret = 0; goto ex;}
3270 	}
3271 	if(d->drive_role == 0) {
3272 		libdax_msgs_submit(libdax_messenger, d->global_index,
3273 			0x00020146,
3274 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
3275 			"Drive is a virtual placeholder (null-drive)", 0, 0);
3276 		{ret = 0; goto ex;}
3277 	}
3278 	if(d->drive_role == 4) {
3279 		libdax_msgs_submit(libdax_messenger, d->global_index,
3280 			0x00020181,
3281 			LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
3282 			"Pseudo-drive is a read-only file. Cannot write.",
3283 			0, 0);
3284 		{ret = 0; goto ex;}
3285 	}
3286 
3287 	if(d->drive_role == 2 || d->drive_role == 5)
3288 		alignment = 2 * 1024;
3289 	if (d->current_profile == 0x12) /* DVD-RAM */
3290 		alignment = 2 * 1024;
3291         if (d->current_profile == 0x13) /* DVD-RW restricted overwrite */
3292 		alignment = 32 * 1024;
3293 	if (d->current_profile == 0x1a) /* DVD+RW */
3294 		alignment = 2 * 1024;
3295 	if (d->current_profile == 0x43) /* BD-RE */
3296 		alignment = 2 * 1024;
3297 	if (alignment == 0) {
3298 		sprintf(msg, "Write start address not supported");
3299 		libdax_msgs_submit(libdax_messenger, d->global_index,
3300 			0x00020125,
3301 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
3302 			"Write start address not supported", 0, 0);
3303 		{ret = 0; goto ex;}
3304 	}
3305 	if ((byte_address % alignment) != 0) {
3306 		sprintf(msg,
3307 			"Write start address not properly aligned (%d bytes)",
3308 			alignment);
3309 		libdax_msgs_submit(libdax_messenger, d->global_index,
3310 			0x00020126,
3311 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
3312 			msg, 0, 0);
3313 		{ret = 0; goto ex;}
3314 	}
3315 	if ((data_count % alignment) != 0) {
3316 		sprintf(msg,
3317 			"Write data count not properly aligned (%ld bytes)",
3318 			(long) alignment);
3319 		libdax_msgs_submit(libdax_messenger, d->global_index,
3320 			0x00020141,
3321 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
3322 			msg, 0, 0);
3323 		{ret = 0; goto ex;}
3324 	}
3325 	if (d->busy != BURN_DRIVE_IDLE) {
3326 		libdax_msgs_submit(libdax_messenger,
3327 			d->global_index, 0x00020140,
3328 			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
3329 			"Drive is busy on attempt to write random access",0,0);
3330 		{ret = 0; goto ex;}
3331 	}
3332 	if (d->drive_role != 1) {
3333 		if (d->stdio_fd >= 0) {
3334 			/* Avoid to have a read-only fd open */
3335 			getfl_ret = fcntl(d->stdio_fd, F_GETFL);
3336 			if (((O_RDWR | O_WRONLY | O_RDONLY) & getfl_ret) ==
3337 			    O_RDONLY) {
3338 				close(d->stdio_fd);
3339 				d->stdio_fd = -1;
3340 			}
3341 		}
3342 		if (d->stdio_fd >= 0) {
3343 			/* Avoid to have two fds open */
3344 			fd = d->stdio_fd;
3345 		} else {
3346 			fd = burn_stdio_open_write(d, byte_address, 2048, 0);
3347 			if (fd == -1)
3348 				{ret = 0; goto ex;}
3349 			do_close = 1;
3350 		}
3351 	}
3352 	d->cancel = 0;
3353 	d->busy = BURN_DRIVE_WRITING_SYNC;
3354 	d->buffer = buf;
3355 
3356 	start = byte_address / 2048;
3357 	upto = start + data_count / 2048;
3358 	rpt = data;
3359 	for (; start < upto; start += 16) {
3360 		chunksize = upto - start;
3361 		if (chunksize > 16)
3362 			chunksize = 16;
3363 		d->buffer->bytes = chunksize * 2048;
3364 		memcpy(d->buffer->data, rpt, d->buffer->bytes);
3365 		rpt += d->buffer->bytes;
3366 		d->buffer->sectors = chunksize;
3367 		d->nwa = start;
3368 		if(d->do_simulate) {
3369 			err = 0;
3370 		} else if(d->drive_role == 1) {
3371 			err = d->write(d, d->nwa, d->buffer);
3372 		} else {
3373 			ret = burn_stdio_write(fd, (char *) d->buffer->data,
3374 						d->buffer->bytes, d, 0);
3375 			err = 0;
3376 			if (ret <= 0)
3377 				err = BE_CANCELLED;
3378 		}
3379 		if (err == BE_CANCELLED) {
3380 			d->busy = BURN_DRIVE_IDLE;
3381 			if(fd >= 0 && do_close)
3382 				close(fd);
3383 			{ret = -(start * 2048 - byte_address); goto ex;}
3384 		}
3385 	}
3386 
3387 	if(d->drive_role == 1)
3388 		d->needs_sync_cache = 1;
3389 	if(flag & 1) {
3390 		if(d->do_simulate) {
3391 			;
3392 		} else if(d->drive_role == 1)
3393 			d->sync_cache(d);
3394 		else
3395 			burn_stdio_sync_cache(fd, d, 2);
3396 		d->needs_sync_cache = 0;
3397 	}
3398 
3399 	if(fd >= 0 && do_close)
3400 		close(fd);
3401 	d->buffer = buffer_mem;
3402 	d->busy = BURN_DRIVE_IDLE;
3403 	ret = 1;
3404 ex:
3405 	BURN_FREE_MEM(buf);
3406 	return ret;
3407 }
3408 
3409 
3410 /* ts B10527 */
3411 /* @param bit0= force close, even if no damage was seen
3412 */
burn_disc_close_damaged(struct burn_write_opts * o,int flag)3413 int burn_disc_close_damaged(struct burn_write_opts *o, int flag)
3414 {
3415 	struct burn_drive *d;
3416 	int ret;
3417 	enum burn_drive_status busy;
3418 
3419 	d = o->drive;
3420 	busy = d->busy;
3421 
3422 	if (busy != BURN_DRIVE_IDLE) {
3423 		libdax_msgs_submit(libdax_messenger,
3424 			d->global_index, 0x00020106,
3425 			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
3426 			"Drive is busy on attempt to close damaged session",
3427 			0, 0);
3428 		{ret = 0; goto ex;}
3429 	}
3430 	if (!((d->next_track_damaged & 1) || (flag & 1))) {
3431 		libdax_msgs_submit(libdax_messenger,
3432 			d->global_index, 0x00020187,
3433 			LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
3434 			"Track not marked as damaged. No action taken.",
3435 			0, 0);
3436 		{ret = 0; goto ex;}
3437 	}
3438 	d->busy = BURN_DRIVE_WRITING;
3439 
3440 	if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
3441 		/* Close CD track and session */
3442 		o->write_type = BURN_WRITE_TAO; /* no action without TAO */
3443 
3444 		/* Send mode page 5 */;
3445 		d->send_write_parameters(d, NULL, -1, o);
3446 
3447 		ret = burn_write_close_session(o);
3448 		if (ret <= 0)
3449 			goto ex;
3450 
3451 	} else if(d->current_profile == 0x11 || d->current_profile == 0x14) {
3452 		/* Close DVD-R[W] track and session */
3453 		o->write_type = BURN_WRITE_TAO; /* no action without TAO */
3454 
3455 		/* Send mode page 5 */;
3456 		d->send_write_parameters(d, NULL, -1, o);
3457 
3458 		ret = burn_disc_close_track_dvd_minus_r(o, 0);
3459 		if (ret <= 0)
3460 			goto ex;
3461 		ret = burn_disc_close_session_dvd_minus_r(o);
3462 		if (ret <= 0)
3463 			goto ex;
3464 
3465 	} else if(d->current_profile == 0x1b || d->current_profile == 0x2b) {
3466 		/* Close DVD+R track and session */
3467 		ret = burn_disc_close_track_dvd_plus_r(o, d->last_track_no, 1);
3468 		if (ret <= 0)
3469 			goto ex;
3470 
3471 	} else if(d->current_profile == 0x41) {
3472 		/* Close BD-R track and session */
3473 		ret = burn_disc_close_track_dvd_plus_r(o, d->last_track_no, 1);
3474 		if (ret <= 0)
3475 			goto ex;
3476 
3477 	} else {
3478 		libdax_msgs_submit(libdax_messenger,
3479 			d->global_index, 0x00020188,
3480 			LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
3481 			"Cannot close damaged track on given media type",
3482 			0, 0);
3483 		{ret = 0; goto ex;}
3484 
3485 	}
3486 	ret = 1;
3487 ex:;
3488 	d->busy = busy;
3489 	/* Record with drive that repair was attempted */
3490 	d->next_track_damaged &= ~1;
3491 	return ret;
3492 }
3493 
3494 
3495