"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/write.c" (30 Jan 2021, 93412 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "write.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    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 
   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) */
  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 */
  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 
  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() */
  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 */
  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 */
  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 
  319 static char cue_printify(char c)
  320 {
  321     if (c >= 32 && c < 127)
  322         return c;
  323     return '#';
  324 }
  325 
  326 
  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 */
  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 */
  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 */
  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 */
  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 */
  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 
  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 
  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 
  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 
  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 
  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 
  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 
 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() */
 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 
 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() */
 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() */
 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 
 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 
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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() */
 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. */
 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 */
 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() */
 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 */
 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 */
 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 */
 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 
 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 */
 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 */
 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