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