"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/drive.c" (30 Jan 2021, 96356 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 "drive.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 - 2020 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 <sys/types.h>
   14 #include <sys/stat.h>
   15 #include <stdlib.h>
   16 #include <unistd.h>
   17 #include <signal.h>
   18 #include <dirent.h>
   19 
   20 /* ts A61007 */
   21 /* #include <a ssert.h> */
   22 
   23 #include <stdio.h>
   24 #include <string.h>
   25 #include <ctype.h>
   26 #include <pthread.h>
   27 #include <errno.h>
   28 #include <fcntl.h>
   29 
   30 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
   31 #ifndef O_BINARY
   32 #define O_BINARY 0
   33 #endif
   34 
   35 #include "libburn.h"
   36 #include "init.h"
   37 #include "drive.h"
   38 #include "transport.h"
   39 #include "debug.h"
   40 #include "init.h"
   41 #include "toc.h"
   42 #include "util.h"
   43 #include "sg.h"
   44 #include "structure.h"
   45 
   46 /* ts A70107 : to get BE_CANCELLED */
   47 #include "error.h"
   48 
   49 /* ts A70219 : for burn_disc_get_write_mode_demands() */
   50 #include "options.h"
   51 
   52 /* A70225 : to learn about eventual Libburn_dvd_r_dl_multi_no_close_sessioN */
   53 #include "write.h"
   54 
   55 /* A70903 : for burn_scsi_setup_drive() */
   56 #include "spc.h"
   57 
   58 /* A90815 : for mmc_obtain_profile_name() */
   59 #include "mmc.h"
   60 
   61 /* B60730 : for Libburn_do_no_immed_defaulT */
   62 #include "os.h"
   63 
   64 #include "libdax_msgs.h"
   65 extern struct libdax_msgs *libdax_messenger;
   66 
   67 static struct burn_drive drive_array[255];
   68 static int drivetop = -1;
   69 
   70 /* ts A80410 : in init.c */
   71 extern int burn_support_untested_profiles;
   72 
   73 /* ts B10312 : in init.c */
   74 extern int burn_drive_role_4_allowed;
   75 
   76 
   77 /* ts A61021 : the unspecific part of sg.c:enumerate_common()
   78 */
   79 int burn_setup_drive(struct burn_drive *d, char *fname)
   80 {
   81     d->devname = strdup(fname);
   82     memset(&d->params, 0, sizeof(struct params));
   83     d->idata = NULL;
   84     d->mdata = NULL;
   85     d->toc_entry = NULL;
   86     d->released = 1;
   87     d->stdio_fd = -1;
   88     d->status = BURN_DISC_UNREADY;
   89     d->erasable = 0;
   90     d->current_profile = -1;
   91     d->do_stream_recording = 0;
   92         d->stream_recording_start= 0;
   93     d->role_5_nwa = 0;
   94 
   95 #ifdef Libburn_do_no_immed_defaulT
   96     d->do_no_immed = Libburn_do_no_immed_defaulT;
   97 #else
   98     d->do_no_immed = 0;
   99 #endif
  100 
  101     d->features = NULL;
  102     d->drive_serial_number = NULL;
  103     d->drive_serial_number_len = -1;
  104     d->media_serial_number = NULL;
  105     d->media_serial_number_len = -1;
  106     return 1;
  107 }
  108 
  109 
  110 /* ts A70903 */
  111 void burn_drive_free_subs(struct burn_drive *d)
  112 {
  113     if (d->idata != NULL)
  114         free((void *) d->idata);
  115     d->idata = NULL;
  116     if (d->mdata != NULL) {
  117         burn_mdata_free_subs(d->mdata);
  118         free((void *) d->mdata);
  119     }
  120     d->mdata = NULL;
  121     if(d->toc_entry != NULL)
  122         free((void *) d->toc_entry);
  123     d->toc_entry = NULL;
  124     if (d->devname != NULL)
  125         free(d->devname);
  126     d->devname = NULL;
  127     if (d->stdio_fd >= 0)
  128         close (d->stdio_fd);
  129     d->stdio_fd = -1;
  130     burn_feature_descr_free(&(d->features), 0);
  131     BURN_FREE_MEM(d->drive_serial_number);
  132     BURN_FREE_MEM(d->media_serial_number);
  133         d->drive_serial_number = d->media_serial_number = NULL;
  134     d->drive_serial_number_len = d->media_serial_number_len = 0;
  135     sg_dispose_drive(d, 0);
  136 }
  137 
  138 
  139 /* ts A60904 : ticket 62, contribution by elmom */
  140 /* splitting former burn_drive_free() (which freed all, into two calls) */
  141 void burn_drive_free(struct burn_drive *d)
  142 {
  143     if (d->global_index == -1)
  144         return;
  145     /* ts A60822 : close open fds before forgetting them */
  146     if (d->drive_role == 1)
  147         if (burn_drive_is_open(d)) {
  148             d->unlock(d);
  149             d->release(d);
  150         }
  151     burn_drive_free_subs(d);
  152     d->global_index = -1;
  153 }
  154 
  155 void burn_drive_free_all(void)
  156 {
  157     int i;
  158 
  159     for (i = 0; i < drivetop + 1; i++)
  160         burn_drive_free(&(drive_array[i]));
  161     drivetop = -1;
  162     memset(drive_array, 0, sizeof(drive_array));
  163 }
  164 
  165 
  166 /* ts A60822 */
  167 int burn_drive_is_open(struct burn_drive *d)
  168 {
  169     if (d->drive_role != 1)
  170         return (d->stdio_fd >= 0);
  171     /* ts A61021 : moved decision to sg.c */
  172     return d->drive_is_open(d);
  173 }
  174 
  175 
  176 /* ts A60906 */
  177 int burn_drive_force_idle(struct burn_drive *d)
  178 {
  179     d->busy = BURN_DRIVE_IDLE;
  180     return 1;
  181 }
  182 
  183 
  184 /* ts A60906 */
  185 int burn_drive_is_released(struct burn_drive *d)
  186 {
  187         return !!d->released;
  188 }
  189 
  190 
  191 /* ts A60906 */
  192 /** Inquires drive status in respect to degree of app usage.
  193     @param return -2 = drive is forgotten 
  194                   -1 = drive is closed (i.e. released explicitly)
  195                    0 = drive is open, not grabbed (after scan, before 1st grab)
  196                    1 = drive is grabbed but BURN_DRIVE_IDLE
  197                    2 = drive is grabbed, synchronous read/write interrupted
  198                   10 = drive is grabbing (BURN_DRIVE_GRABBING)
  199                  100 = drive is busy in cancelable state
  200                 1000 = drive is in non-cancelable state 
  201            Expect a monotonous sequence of usage severity to emerge in future.
  202 */
  203 int burn_drive_is_occupied(struct burn_drive *d)
  204 {
  205     if(d->global_index < 0)
  206         return -2;
  207     if(!burn_drive_is_open(d))
  208         return -1;
  209     if(d->busy == BURN_DRIVE_GRABBING)
  210         return 10;
  211     if(d->released)
  212         return 0;
  213     if(d->busy == BURN_DRIVE_IDLE)
  214         return 1;
  215     if(d->busy == BURN_DRIVE_READING_SYNC ||
  216          d->busy == BURN_DRIVE_WRITING_SYNC)
  217         return 2;
  218     if(d->busy == BURN_DRIVE_WRITING ||
  219        d->busy == BURN_DRIVE_WRITING_LEADIN ||
  220        d->busy == BURN_DRIVE_WRITING_LEADOUT ||
  221        d->busy == BURN_DRIVE_WRITING_PREGAP) {
  222 
  223         /* ts A70928 */
  224         /* >>> how do i learn whether the writer thread is still
  225              alive ? */;
  226             /* >>> what to do if writer is dead ? 
  227                 At least sync disc ?*/;
  228         return 50;
  229     }
  230     if(d->busy == BURN_DRIVE_READING) {
  231         return 50;
  232     }
  233     return 1000;
  234 }
  235 
  236 
  237 /*
  238 void drive_read_lead_in(int dnum)
  239 {
  240     mmc_read_lead_in(&drive_array[dnum], get_4k());
  241 }
  242 */
  243 unsigned int burn_drive_count(void)
  244 {
  245     return drivetop + 1;
  246 }
  247 
  248 
  249 /* ts A80801 */
  250 int burn_drive_is_listed(char *path, struct burn_drive **found, int flag)
  251 {
  252     int i, ret;
  253     char *drive_adr = NULL, *off_adr = NULL;
  254 
  255     BURN_ALLOC_MEM(drive_adr, char, BURN_DRIVE_ADR_LEN);
  256     BURN_ALLOC_MEM(off_adr, char, BURN_DRIVE_ADR_LEN);
  257 
  258     ret = burn_drive_convert_fs_adr(path, off_adr);
  259     if (ret <= 0)
  260         strcpy(off_adr, path);
  261     for (i = 0; i <= drivetop; i++) {
  262         if (drive_array[i].global_index < 0)
  263     continue;
  264         ret = burn_drive_d_get_adr(&(drive_array[i]), drive_adr);
  265         if (ret <= 0)
  266     continue;
  267         if(strcmp(off_adr, drive_adr) == 0) {
  268             if (found != NULL)
  269                 *found= &(drive_array[i]);
  270             {ret= 1; goto ex;}
  271         }
  272     }
  273     ret= 0;
  274 ex:;
  275     BURN_FREE_MEM(drive_adr);
  276     BURN_FREE_MEM(off_adr);
  277     return ret;
  278 }
  279 
  280 
  281 /* ts A61125 : media status aspects of burn_drive_grab() */
  282 int burn_drive_inquire_media(struct burn_drive *d)
  283 {
  284 
  285     /* ts A61225 : after loading the tray, mode page 2Ah can change */
  286     d->getcaps(d);
  287 
  288     /* ts A61020 : d->status was set to BURN_DISC_BLANK as pure guess */
  289 
  290         /* ts A71128 : run read_disc_info() for any recognizable profile */
  291     if (d->current_profile > 0 || d->current_is_guessed_profile ||
  292         (d->mdata->p2a_valid > 0 &&
  293         (d->mdata->cdr_write || d->mdata->cdrw_write ||
  294          d->mdata->dvdr_write || d->mdata->dvdram_write)) ) {
  295         d->read_disc_info(d);
  296     } else {
  297         if (d->current_profile == -1 || d->current_is_cd_profile)
  298             d->read_toc(d);
  299 
  300         /* ts A70314 , B10712 */
  301         if (d->status != BURN_DISC_EMPTY)
  302             d->status = BURN_DISC_UNSUITABLE;
  303     }
  304     return 1;
  305 }
  306 
  307 /* ts B10730 */
  308 /* Send a default mode page 05 to CD and DVD-R-oids */
  309 int burn_drive_send_default_page_05(struct burn_drive *d, int flag)
  310 {
  311     struct burn_write_opts *opts;
  312 
  313     if (d->sent_default_page_05)
  314         return 0;
  315     if (!((d->status == BURN_DISC_APPENDABLE ||
  316                d->status == BURN_DISC_BLANK) &&
  317               (d->current_is_cd_profile || d->current_profile == 0x11 ||
  318            d->current_profile == 0x14 || d->current_profile == 0x15)))
  319         return 0;
  320     opts = burn_write_opts_new(d);
  321     if (opts == NULL)
  322         return -1;
  323     if (d->status == BURN_DISC_APPENDABLE)
  324         burn_write_opts_set_write_type(opts,
  325             BURN_WRITE_TAO, BURN_BLOCK_MODE1);
  326     else
  327         burn_write_opts_set_write_type(opts,
  328             BURN_WRITE_SAO, BURN_BLOCK_SAO);
  329     d->send_write_parameters(d, NULL, -1, opts);
  330     burn_write_opts_free(opts);
  331     d->sent_default_page_05 = 1;
  332     return 1;
  333 }
  334 
  335 
  336 /* ts A70924 */
  337 int burn_drive__fd_from_special_adr(char *adr)
  338 {
  339     int fd = -1, i;
  340 
  341     if (strcmp(adr, "-") == 0)
  342         fd = 1;
  343     if(strncmp(adr, "/dev/fd/", 8) == 0) {
  344         for (i = 8; adr[i]; i++)
  345             if (!isdigit(adr[i]))
  346         break;
  347         if (i> 8 && adr[i] == 0)
  348             fd = atoi(adr + 8);
  349     }
  350     return fd;
  351 }
  352 
  353 /* @param flag bit0= accept read-only files and return 2 in this case
  354                bit1= accept write-only files and return 3 in this case
  355 */
  356 static int burn_drive__is_rdwr(char *fname, int *stat_ret, 
  357                                struct stat *stbuf_ret,
  358                                off_t *read_size_ret, int flag)
  359 {
  360     int fd, is_rdwr = 1, ret, getfl_ret, st_ret, mask;
  361     struct stat stbuf;
  362         off_t read_size = 0;
  363 
  364     memset(&stbuf, 0, sizeof(struct stat));
  365     fd = burn_drive__fd_from_special_adr(fname);
  366     if (fd >= 0)
  367         st_ret = fstat(fd, &stbuf);
  368     else
  369         st_ret = stat(fname, &stbuf);
  370     if (st_ret != -1) {
  371         is_rdwr = burn_os_is_2k_seekrw(fname, 0);
  372         ret = 1;
  373         if (S_ISREG(stbuf.st_mode))
  374             read_size = stbuf.st_size;
  375         else if (is_rdwr)
  376             ret = burn_os_stdio_capacity(fname, 0, &read_size);
  377         if (ret <= 0 ||
  378             read_size / (off_t) 2048 >= (off_t) 0x7ffffff0) 
  379             read_size = (off_t) 0x7ffffff0 * (off_t) 2048;  
  380     }
  381 
  382     if (is_rdwr && fd >= 0) {
  383         getfl_ret = fcntl(fd, F_GETFL);
  384 
  385 /*
  386 fprintf(stderr, "LIBBURN_DEBUG: burn_drive__is_rdwr: getfl_ret = %lX , O_RDWR = %lX , & = %lX , O_RDONLY = %lX\n", (unsigned long) getfl_ret, (unsigned long) O_RDWR, (unsigned long) (getfl_ret & O_RDWR), (unsigned long) O_RDONLY);
  387 */
  388 
  389         mask = O_RDWR | O_WRONLY | O_RDONLY;
  390 
  391         if (getfl_ret == -1 || (getfl_ret & mask) != O_RDWR)
  392             is_rdwr = 0;
  393         if ((flag & 1) && getfl_ret != -1 &&
  394             (getfl_ret & mask) == O_RDONLY)
  395             is_rdwr = 2;
  396         if ((flag & 2) && getfl_ret != -1 &&
  397             (getfl_ret & mask) == O_WRONLY)
  398             is_rdwr = 3;
  399     }
  400     if (stat_ret != NULL)
  401         *stat_ret = st_ret;
  402     if (stbuf_ret != NULL)
  403         memcpy(stbuf_ret, &stbuf, sizeof(struct stat));
  404     if (read_size_ret != NULL)
  405         *read_size_ret = read_size;
  406     return is_rdwr;
  407 }
  408 
  409 
  410 /* flag bit0= ( not needed yet: grab even if it is already grabbed )
  411 */
  412 int burn_drive_grab_stdio(struct burn_drive *d, int flag)
  413 {
  414     int stat_ret = -1, is_rdwr, ret;
  415     struct stat stbuf;
  416     off_t read_size= 0, size= 0;
  417     char fd_name[40], *name_pt = NULL;
  418 
  419     if(d->stdio_fd >= 0) {
  420         sprintf(fd_name, "/dev/fd/%d", d->stdio_fd);
  421         name_pt = fd_name;
  422     } else if (d->devname[0]) {
  423         name_pt = d->devname;
  424     }
  425     if (name_pt != NULL) {
  426         /* re-assess d->media_read_capacity and free space */
  427         is_rdwr = burn_drive__is_rdwr(name_pt, &stat_ret, &stbuf,
  428                              &read_size, 1 | 2);
  429         /* despite its name : last valid address, not size */
  430         d->media_read_capacity =
  431                     read_size / 2048 - !(read_size % 2048);
  432         d->mr_capacity_trusted = 1;
  433         if ((stat_ret == -1 || is_rdwr) && d->devname[0]) { 
  434                 ret = burn_os_stdio_capacity(d->devname, 0, &size);
  435             if (ret > 0)
  436                 burn_drive_set_media_capacity_remaining(d,
  437                                     size);
  438         }
  439     }
  440 
  441     d->released = 0;
  442     d->current_profile = 0xffff;
  443     if(d->drive_role == 2 || d->drive_role == 3) {
  444         d->status = BURN_DISC_BLANK;
  445     } else if(d->drive_role == 4) {
  446         if (d->media_read_capacity > 0)
  447             d->status = BURN_DISC_FULL;
  448         else
  449             d->status = BURN_DISC_EMPTY;
  450     } else if(d->drive_role == 5) {
  451         if (stat_ret != -1 && S_ISREG(stbuf.st_mode) &&
  452             stbuf.st_size > 0) {
  453             d->status = BURN_DISC_APPENDABLE;
  454             if (stbuf.st_size / (off_t) 2048
  455                 >= 0x7ffffff0) {
  456                 d->status = BURN_DISC_FULL;
  457                 d->role_5_nwa = 0x7ffffff0;
  458             } else 
  459                 d->role_5_nwa = stbuf.st_size / 2048 +
  460                               !!(stbuf.st_size % 2048);
  461         } else
  462             d->status = BURN_DISC_BLANK;
  463     } else {
  464         d->status = BURN_DISC_EMPTY;
  465         d->current_profile = 0;
  466     }
  467     d->busy = BURN_DRIVE_IDLE;
  468     return 1;
  469 }
  470 
  471 
  472 int burn_drive_grab(struct burn_drive *d, int le)
  473 {
  474     int errcode;
  475     /* ts A61125 - B20122 */
  476     int ret, sose, signal_action_mem = -1;
  477 
  478     sose = d->silent_on_scsi_error;
  479     if (!d->released) {
  480                 libdax_msgs_submit(libdax_messenger, d->global_index,
  481                                 0x00020189, LIBDAX_MSGS_SEV_FATAL,
  482                                 LIBDAX_MSGS_PRIO_LOW,
  483                 "Drive is already grabbed by libburn", 0, 0);
  484         return 0;
  485     }
  486     if(d->drive_role != 1) {
  487         ret = burn_drive_grab_stdio(d, 0);
  488         return ret;
  489     }
  490 
  491     d->status = BURN_DISC_UNREADY;
  492     errcode = d->grab(d);
  493     if (errcode == 0)
  494         return 0;
  495 
  496     burn_grab_prepare_sig_action(&signal_action_mem, 0);
  497     d->busy = BURN_DRIVE_GRABBING;
  498 
  499     if (le)
  500         d->load(d);
  501     if (d->cancel || burn_is_aborting(0))
  502         {ret = 0; goto ex;}
  503 
  504     d->lock(d);
  505     if (d->cancel || burn_is_aborting(0))
  506         {ret = 0; goto ex;}
  507 
  508     /* ts A61118 */
  509     d->start_unit(d);
  510     if (d->cancel || burn_is_aborting(0))
  511         {ret = 0; goto ex;}
  512 
  513     /* ts A61202 : gave bit1 of le a meaning */
  514     if (!le)
  515         d->silent_on_scsi_error = 1;
  516     /* ts A61125 : outsourced media state inquiry aspects */
  517     ret = burn_drive_inquire_media(d);
  518     if (d->cancel || burn_is_aborting(0))
  519         {ret = 0; goto ex;}
  520 
  521     burn_drive_send_default_page_05(d, 0);
  522     if (d->cancel || burn_is_aborting(0))
  523         {ret = 0; goto ex;}
  524 
  525 ex:;
  526     if (d->cancel || burn_is_aborting(0)) {
  527             d->unlock(d);
  528         d->release(d);
  529     }
  530     d->silent_on_scsi_error = sose;
  531     d->busy = BURN_DRIVE_IDLE;
  532     burn_grab_restore_sig_action(signal_action_mem, 0);
  533     return ret;
  534 }
  535 
  536 
  537 /* ts A71015 */
  538 #define Libburn_ticket_62_re_register_is_possiblE 1
  539 
  540 struct burn_drive *burn_drive_register(struct burn_drive *d)
  541 {
  542 #ifdef Libburn_ticket_62_re_register_is_possiblE
  543     int i;
  544 #endif
  545 
  546     d->block_types[0] = 0;
  547     d->block_types[1] = 0;
  548     d->block_types[2] = 0;
  549     d->block_types[3] = 0;
  550     d->toc_temp = 0;
  551     d->nwa = 0;
  552     d->alba = 0;
  553     d->rlba = 0;
  554     d->cancel = 0;
  555     d->busy = BURN_DRIVE_IDLE;
  556     d->thread_pid = 0;
  557     d->thread_pid_valid = 0;
  558     memset(&(d->thread_tid), 0, sizeof(d->thread_tid));
  559     d->medium_state_changed = 0;
  560     d->set_streaming_exact_bit = 0;
  561     d->set_streaming_err = 0;
  562     d->toc_entries = 0;
  563     d->toc_entry = NULL;
  564     d->disc = NULL;
  565     d->erasable = 0;
  566     d->write_opts = NULL;
  567 
  568 #ifdef Libburn_ticket_62_re_register_is_possiblE
  569     /* ts A60904 : ticket 62, contribution by elmom */
  570     /* Not yet accepted because no use case seen yet */
  571         /* ts A71015 : xorriso dialog imposes a use case now */
  572 
  573     /* This is supposed to find an already freed drive struct among
  574        all the the ones that have been used before */
  575     for (i = 0; i < drivetop + 1; i++)
  576         if (drive_array[i].global_index == -1)
  577             break;
  578     d->global_index = i;
  579     memcpy(&drive_array[i], d, sizeof(struct burn_drive));
  580     pthread_mutex_init(&drive_array[i].access_lock, NULL);
  581     if (drivetop < i)
  582         drivetop = i;
  583     return &(drive_array[i]);
  584 
  585 #else /* Libburn_ticket_62_re_register_is_possiblE */
  586     /* old A60904 : */
  587     /* Still active by default */
  588 
  589     d->global_index = drivetop + 1;
  590     memcpy(&drive_array[drivetop + 1], d, sizeof(struct burn_drive));
  591     pthread_mutex_init(&drive_array[drivetop + 1].access_lock, NULL);
  592     return &drive_array[++drivetop];
  593 
  594 #endif /* ! Libburn_ticket_62_re_register_is_possiblE */
  595 
  596 }
  597 
  598 
  599 /* unregister most recently registered drive */
  600 int burn_drive_unregister(struct burn_drive *d)
  601 {
  602     if(d->global_index != drivetop)
  603         return 0;
  604     burn_drive_free(d);
  605     drivetop--;
  606     return 1;
  607 }
  608 
  609 
  610 /* ts A61021 : after-setup activities from sg.c:enumerate_common()
  611 */
  612 struct burn_drive *burn_drive_finish_enum(struct burn_drive *d)
  613 {
  614     struct burn_drive *t = NULL;
  615     char *msg = NULL;
  616     int ret;
  617 
  618     BURN_ALLOC_MEM(msg, char, BURN_DRIVE_ADR_LEN + 160);
  619 
  620     d->drive_role = 1; /* MMC drive */
  621 
  622     t = burn_drive_register(d);
  623 
  624     /* ts A60821 */
  625     mmc_function_spy(NULL, "enumerate_common : -------- doing grab");
  626 
  627     /* try to get the drive info */
  628     ret = t->grab(t);
  629     if (ret) {
  630             t->getcaps(t);
  631             t->unlock(t);
  632             t->released = 1;
  633     } else {
  634         /* ts A90602 */
  635         d->mdata->p2a_valid = -1;
  636                 sprintf(msg, "Unable to grab scanned drive %s", d->devname);
  637                 libdax_msgs_submit(libdax_messenger, d->global_index,
  638                                 0x0002016f, LIBDAX_MSGS_SEV_DEBUG,
  639                                 LIBDAX_MSGS_PRIO_LOW, msg, 0, 0);
  640             burn_drive_unregister(t);
  641         t = NULL;
  642     }
  643 
  644     /* ts A60821 */
  645     mmc_function_spy(NULL, "enumerate_common : ----- would release ");
  646 
  647 ex:
  648     BURN_FREE_MEM(msg);
  649     return t;
  650 }
  651 
  652 
  653 /* ts A61125 : model aspects of burn_drive_release */
  654 /* @param flag bit3= do not close d->stdio_fd
  655 */
  656 int burn_drive_mark_unready(struct burn_drive *d, int flag)
  657 {
  658     /* ts A61020 : mark media info as invalid */
  659     d->start_lba= -2000000000;
  660     d->end_lba= -2000000000;
  661 
  662     /* ts A61202 */
  663     d->current_profile = -1;
  664     d->current_has_feat21h = 0;
  665     d->current_feat2fh_byte4 = -1;
  666 
  667     d->status = BURN_DISC_UNREADY;
  668     if (d->toc_entry != NULL)
  669         free(d->toc_entry);
  670     d->toc_entry = NULL;
  671     d->toc_entries = 0;
  672     if (d->write_opts != NULL) {
  673         burn_write_opts_free(d->write_opts);
  674         d->write_opts = NULL;
  675     }
  676     if (d->disc != NULL) {
  677         burn_disc_free(d->disc);
  678         d->disc = NULL;
  679     }
  680     if (!(flag & 8)) {
  681         if (d->stdio_fd >= 0)
  682             close (d->stdio_fd);
  683         d->stdio_fd = -1;
  684     }
  685     return 1;
  686 }
  687 
  688 
  689 /* ts A70918 : outsourced from burn_drive_release() and enhanced */
  690 /** @param flag bit0-2 = mode : 0=unlock , 1=unlock+eject , 2=leave locked
  691                 bit3= do not call d->release()
  692 */
  693 int burn_drive_release_fl(struct burn_drive *d, int flag)
  694 {
  695     if (d->released) {
  696         /* ts A61007 */
  697         libdax_msgs_submit(libdax_messenger,
  698                 d->global_index, 0x00020105,
  699                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  700                 "Drive is already released", 0, 0);
  701         return 0;
  702     }
  703 
  704     /* ts A61007 */
  705     /* ts A60906: one should not assume BURN_DRIVE_IDLE == 0 */
  706     /* a ssert(d->busy == BURN_DRIVE_IDLE); */
  707     if (d->busy != BURN_DRIVE_IDLE) {
  708         libdax_msgs_submit(libdax_messenger,
  709                 d->global_index, 0x00020106,
  710                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  711                 "Drive is busy on attempt to close", 0, 0);
  712         return 0;
  713     }
  714 
  715     if (d->drive_role == 1) {
  716         if (d->needs_sync_cache)
  717             d->sync_cache(d);
  718         if ((flag & 7) != 2)
  719             d->unlock(d);
  720         if ((flag & 7) == 1)
  721             d->eject(d);
  722         if (!(flag & 8)) {
  723             burn_drive_snooze(d, 0);
  724             d->release(d);
  725         }
  726     }
  727 
  728     d->needs_sync_cache = 0; /* just to be sure */
  729 
  730     if (d->drive_serial_number != NULL)
  731         BURN_FREE_MEM(d->drive_serial_number);
  732     if (d->media_serial_number != NULL)
  733         BURN_FREE_MEM(d->media_serial_number);
  734     d->drive_serial_number = d->media_serial_number = NULL;
  735     d->drive_serial_number_len = d->media_serial_number_len = 0;
  736 
  737     d->released = 1;
  738 
  739     /* ts A61125 : outsourced model aspects */
  740     burn_drive_mark_unready(d, flag & 8);
  741     return 1;
  742 }
  743 
  744 
  745 /* API */
  746 /* ts A90824
  747    @param flag bit0= wake up (else start snoozing)
  748 */
  749 int burn_drive_snooze(struct burn_drive *d, int flag)
  750 {
  751     if (d->drive_role != 1)
  752         return 0;
  753     if (flag & 1)
  754         d->start_unit(d);
  755     else
  756         d->stop_unit(d);
  757     return 1;
  758 }
  759 
  760 
  761 /* API */
  762 void burn_drive_release(struct burn_drive *d, int le)
  763 {
  764     burn_drive_release_fl(d, !!le);
  765 }
  766 
  767 
  768 /* ts B11002 */
  769 /* API */
  770 int burn_drive_re_assess(struct burn_drive *d, int flag)
  771 {
  772     int ret, signal_action_mem;
  773 
  774     if (d->released) {
  775         libdax_msgs_submit(libdax_messenger, d->global_index,
  776                  0x00020108,
  777                  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  778                  "Drive is not grabbed on burn_drive_re_assess()",
  779                  0, 0);
  780         return 0;
  781     }
  782     burn_drive_release_fl(d, 2 | 8);
  783 
  784     if(d->drive_role != 1) {
  785         ret = burn_drive_grab_stdio(d, 0);
  786         return ret;
  787     }
  788 
  789     burn_grab_prepare_sig_action(&signal_action_mem, 0);
  790     d->busy = BURN_DRIVE_GRABBING;
  791     ret = burn_drive_inquire_media(d);
  792     burn_drive_send_default_page_05(d, 0);
  793     d->busy = BURN_DRIVE_IDLE;
  794     burn_grab_restore_sig_action(signal_action_mem, 0);
  795     d->released = 0;
  796     return ret;
  797 }
  798 
  799 
  800 /* ts A70918 */
  801 /* API */
  802 int burn_drive_leave_locked(struct burn_drive *d, int flag)
  803 {
  804     return burn_drive_release_fl(d, 2);
  805 }
  806 
  807 
  808 /* ts A61007 : former void burn_wait_all() */
  809 /* @param flag  bit0= demand freed drives (else released drives) */
  810 int burn_drives_are_clear(int flag)
  811 {
  812     int i;
  813 
  814     for (i = burn_drive_count() - 1; i >= 0; --i) {
  815         /* ts A60904 : ticket 62, contribution by elmom */
  816         if (drive_array[i].global_index == -1)
  817     continue;
  818         if (drive_array[i].released && !(flag & 1))
  819     continue;
  820         return 0;
  821     }
  822     return 1;
  823 }
  824 
  825 
  826 #if 0
  827 void burn_wait_all(void)
  828 {
  829     unsigned int i;
  830     int finished = 0;
  831     struct burn_drive *d;
  832 
  833     while (!finished) {
  834         finished = 1;
  835         d = drive_array;
  836         for (i = burn_drive_count(); i > 0; --i, ++d) {
  837 
  838             /* ts A60904 : ticket 62, contribution by elmom */
  839             if (d->global_index==-1)
  840                 continue;
  841 
  842             a ssert(d->released); 
  843         }
  844         if (!finished)
  845             sleep(1);
  846     }
  847 }
  848 #endif
  849 
  850 
  851 void burn_disc_erase_sync(struct burn_drive *d, int fast)
  852 {
  853     int ret, was_error = 0;
  854 
  855     if (d->drive_role == 5) { /* Random access write-only drive */
  856         ret = truncate(d->devname, (off_t) 0);
  857         if (ret == -1) {
  858             libdax_msgs_submit(libdax_messenger, -1,
  859                  0x00020182,
  860                  LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  861                  "Cannot truncate disk file for pseudo blanking",
  862                  0, 0);
  863             return;
  864         }
  865         d->role_5_nwa = 0;
  866         d->cancel = 0;
  867         d->status = BURN_DISC_BLANK;
  868         d->busy = BURN_DRIVE_IDLE;
  869         d->progress.sector = 0x10000;
  870         return;
  871     }
  872 
  873     d->cancel = 0;
  874 
  875 #ifdef Libburn_reset_progress_asynC
  876     /* <<< This is now done in async.c */
  877     /* reset the progress */
  878     d->progress.session = 0;
  879     d->progress.sessions = 1;
  880     d->progress.track = 0;
  881     d->progress.tracks = 1;
  882     d->progress.index = 0;
  883     d->progress.indices = 1;
  884     d->progress.start_sector = 0;
  885     d->progress.sectors = 0x10000;
  886     d->progress.sector = 0;
  887 #endif /* Libburn_reset_progress_asynC */
  888 
  889     d->medium_state_changed = 1;
  890     d->erase(d, fast);
  891     d->busy = BURN_DRIVE_ERASING;
  892 
  893 #ifdef Libburn_old_progress_looP
  894 
  895     /* read the initial 0 stage */
  896     while (!d->test_unit_ready(d) && d->get_erase_progress(d) == 0)
  897         sleep(1);
  898     while ((d->progress.sector = d->get_erase_progress(d)) > 0 ||
  899         !d->test_unit_ready(d))
  900         sleep(1);
  901 
  902 #else /* Libburn_old_progress_looP */
  903 
  904     while (1) {
  905 
  906         /* >>> ??? ts B60730 : abort if user interrupts ?
  907         if (d->cancel)
  908     break;
  909         */
  910 
  911         ret = d->get_erase_progress(d);
  912         if (ret == -2 || ret > 0)
  913     break;
  914         if (ret == -3)
  915             was_error = 1;
  916         sleep(1);
  917     }
  918     while (1) {
  919 
  920         /* >>> ??? ts B60730 : abort if user interrupts ?
  921         if (d->cancel)
  922     break;
  923         */
  924 
  925         ret = d->get_erase_progress(d);
  926         if(ret == -2)
  927     break;
  928         if (ret == -3)
  929             was_error = 1;
  930         if (ret >= 0)
  931             d->progress.sector = ret;
  932         sleep(1);
  933         }
  934 
  935 #endif /* ! Libburn_old_progress_looP */
  936 
  937     d->progress.sector = 0x10000;
  938 
  939     /* ts A61125 : update media state records */
  940     burn_drive_mark_unready(d, 0);
  941     if (d->drive_role == 1 && !d->cancel)
  942         burn_drive_inquire_media(d);
  943     d->busy = BURN_DRIVE_IDLE;
  944     if (was_error)
  945         d->cancel = 1;
  946 }
  947 
  948 /*
  949    @param flag: bit0 = fill formatted size with zeros
  950                 bit1, bit2 , bit4, bit5, bit7 - bit15 are for d->format_unit()
  951 */
  952 void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag)
  953 {
  954     int ret, buf_secs, err, i, stages = 1, pbase, pfill, pseudo_sector;
  955     int was_error = 0;
  956     off_t num_bufs;
  957     char msg[80];
  958     struct buffer *buf = NULL, *buf_mem = d->buffer;
  959 
  960     BURN_ALLOC_MEM(buf, struct buffer, 1);
  961 
  962 #ifdef Libburn_reset_progress_asynC
  963     /* <<< This is now done in async.c */
  964     /* reset the progress */
  965     d->progress.session = 0;
  966     d->progress.sessions = 1;
  967     d->progress.track = 0;
  968     d->progress.tracks = 1;
  969     d->progress.index = 0;
  970     d->progress.indices = 1;
  971     d->progress.start_sector = 0;
  972     d->progress.sectors = 0x10000;
  973     d->progress.sector = 0;
  974 #endif /* Libburn_reset_progress_asynC */
  975 
  976     stages = 1 + ((flag & 1) && size > 1024 * 1024);
  977     d->cancel = 0;
  978     d->busy = BURN_DRIVE_FORMATTING;
  979     d->medium_state_changed = 1;
  980 
  981     ret = d->format_unit(d, size, flag & 0xfff6); /* forward bits */
  982     if (ret <= 0)
  983         d->cancel = 1;
  984 
  985 #ifdef Libburn_old_progress_looP
  986 
  987     while (!d->test_unit_ready(d) && d->get_erase_progress(d) == 0)
  988         sleep(1);
  989     while ((pseudo_sector = d->get_erase_progress(d)) > 0 ||
  990         !d->test_unit_ready(d)) {
  991         d->progress.sector = pseudo_sector / stages;
  992         sleep(1);
  993         }
  994 
  995 #else /* Libburn_old_progress_looP */
  996 
  997     while (1) {
  998         ret = d->get_erase_progress(d);
  999         if (ret == -2 || ret > 0)
 1000     break;
 1001         if (ret == -3)
 1002             was_error = 1;
 1003         sleep(1);
 1004     }
 1005     while (1) {
 1006         pseudo_sector = d->get_erase_progress(d);
 1007         if(pseudo_sector == -2)
 1008     break;
 1009         if (pseudo_sector == -3)
 1010             was_error = 1;
 1011         if (pseudo_sector >= 0)
 1012             d->progress.sector = pseudo_sector / stages;
 1013         sleep(1);
 1014         }
 1015 
 1016 #endif /* ! Libburn_old_progress_looP */
 1017 
 1018     d->sync_cache(d);
 1019 
 1020     if (size <= 0)
 1021         goto ex;
 1022 
 1023     /* update media state records */
 1024     burn_drive_mark_unready(d, 0);
 1025     burn_drive_inquire_media(d);
 1026     if (flag & 1) {
 1027         /* write size in zeros */;
 1028         pbase = 0x8000 + 0x7fff * (stages == 1);
 1029         pfill = 0xffff - pbase;
 1030         buf_secs = 16; /* Must not be more than 16 */
 1031         num_bufs = size / buf_secs / 2048;
 1032         if (num_bufs > 0x7fffffff) {
 1033             d->cancel = 1;
 1034             goto ex;
 1035         }
 1036 
 1037         /* <<< */
 1038         sprintf(msg,
 1039             "Writing %.f sectors of zeros to formatted media",
 1040             (double) num_bufs * (double) buf_secs);
 1041         libdax_msgs_submit(libdax_messenger, d->global_index,
 1042                 0x00000002,
 1043                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
 1044                 msg, 0, 0);
 1045 
 1046         d->buffer = buf;
 1047         memset(d->buffer, 0, sizeof(struct buffer));
 1048         d->buffer->bytes = buf_secs * 2048;
 1049         d->buffer->sectors = buf_secs;
 1050         d->busy = BURN_DRIVE_WRITING;
 1051         for (i = 0; i < num_bufs; i++) {
 1052             d->nwa = i * buf_secs;
 1053             err = d->write(d, d->nwa, d->buffer);
 1054             if (err == BE_CANCELLED || d->cancel) {
 1055                 d->cancel = 1;
 1056         break;
 1057             }
 1058             d->progress.sector = pbase
 1059                 + pfill * ((double) i / (double) num_bufs);
 1060         }
 1061         d->sync_cache(d);
 1062         if (d->current_profile == 0x13 || d->current_profile == 0x1a) {
 1063             /* DVD-RW or DVD+RW */
 1064             d->busy = BURN_DRIVE_CLOSING_SESSION;
 1065             /* CLOSE SESSION, 010b */
 1066             d->close_track_session(d, 1, 0);
 1067             d->busy = BURN_DRIVE_WRITING;
 1068         }
 1069     }
 1070 ex:;
 1071     d->progress.sector = 0x10000;
 1072     d->busy = BURN_DRIVE_IDLE;
 1073     d->buffer = buf_mem;
 1074     if (was_error)
 1075         d->cancel = 1;
 1076     BURN_FREE_MEM(buf);
 1077 }
 1078 
 1079 
 1080 /* ts A70112 API */
 1081 int burn_disc_get_formats(struct burn_drive *d, int *status, off_t *size,
 1082                 unsigned *bl_sas, int *num_formats)
 1083 {
 1084     int ret;
 1085 
 1086     *status = 0;
 1087     *size = 0;
 1088     *bl_sas = 0;
 1089     *num_formats = 0;
 1090     if (d->drive_role != 1)
 1091         return 0;
 1092     ret = d->read_format_capacities(d, 0x00);
 1093     if (ret <= 0)
 1094         return 0;
 1095     *status = d->format_descr_type;
 1096     *size = d->format_curr_max_size;
 1097     *bl_sas = d->format_curr_blsas;
 1098     *num_formats = d->num_format_descr;
 1099     return 1;
 1100 }
 1101 
 1102 
 1103 /* ts A70112 API */
 1104 int burn_disc_get_format_descr(struct burn_drive *d, int index,
 1105                 int *type, off_t *size, unsigned *tdp)
 1106 {
 1107     *type = 0;
 1108     *size = 0;
 1109     *tdp = 0;
 1110     if (index < 0 || index >= d->num_format_descr)
 1111         return 0;
 1112     *type = d->format_descriptors[index].type;
 1113     *size = d->format_descriptors[index].size;
 1114     *tdp = d->format_descriptors[index].tdp;
 1115     return 1;
 1116 }
 1117 
 1118 
 1119 enum burn_disc_status burn_disc_get_status(struct burn_drive *d)
 1120 {
 1121     /* ts A61007 */
 1122     /* a ssert(!d->released); */
 1123     if (d->released) {
 1124         libdax_msgs_submit(libdax_messenger,
 1125                 d->global_index, 0x00020108,
 1126                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1127                 "Drive is not grabbed on disc status inquiry",
 1128                 0, 0);
 1129         return BURN_DISC_UNGRABBED;
 1130     }
 1131 
 1132     return d->status;
 1133 }
 1134 
 1135 int burn_disc_erasable(struct burn_drive *d)
 1136 {
 1137     return d->erasable;
 1138 }
 1139 enum burn_drive_status burn_drive_get_status(struct burn_drive *d,
 1140                          struct burn_progress *p)
 1141 {
 1142     /* --- Part of asynchronous signal handling --- */
 1143     /* This frequently used call may be used to react on messages from
 1144        the libburn built-in signal handler.
 1145     */
 1146 
 1147     /* ts B00225 :
 1148        If aborting with action 2:
 1149        catch control thread after it returned from signal handler.
 1150        Let it run burn_abort(4440,...) 
 1151     */
 1152     burn_init_catch_on_abort(0);
 1153 
 1154     /* ts A70928 : inform control thread of signal in sub-threads */
 1155     if (burn_builtin_triggered_action < 2 && burn_global_abort_level > 0)
 1156         burn_global_abort_level++;
 1157     if (burn_builtin_triggered_action < 2 && burn_global_abort_level > 5) {
 1158         if (burn_global_signal_handler == NULL)
 1159             kill(getpid(), burn_global_abort_signum);
 1160         else
 1161             (*burn_global_signal_handler)
 1162                 (burn_global_signal_handle,
 1163                  burn_global_abort_signum, 0);
 1164         burn_global_abort_level = -1;
 1165     }
 1166 
 1167     /* --- End of asynchronous signal handling --- */
 1168 
 1169 
 1170     if (p != NULL) {
 1171         memcpy(p, &(d->progress), sizeof(struct burn_progress));
 1172         /* TODO: add mutex */
 1173     }
 1174     return d->busy;
 1175 }
 1176 
 1177 
 1178 int burn_drive_set_stream_recording(struct burn_drive *d, int recmode,
 1179                                     int start, int flag)
 1180 {
 1181 #ifndef Libburn_force_stream_recordinG
 1182     struct burn_feature_descr *descr;
 1183 #endif
 1184 
 1185     if (recmode == 1) {
 1186 
 1187 #ifdef Libburn_force_stream_recordinG
 1188 
 1189         d->do_stream_recording = 1;
 1190 
 1191 #else /* Libburn_force_stream_recordinG */
 1192 
 1193         d->do_stream_recording = 0;
 1194         if (burn_drive_has_feature(d, 0x107, &descr, 0)) {
 1195             if ((descr->data[0] & 1) && (descr->flags & 1))
 1196                 d->do_stream_recording = 1;
 1197         }
 1198         if (!d->do_stream_recording) {
 1199             libdax_msgs_submit(libdax_messenger, d->global_index,
 1200                 0x000201ac,
 1201                 LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
 1202                  "Drive currently does not offer Stream Recording",
 1203                 0, 0);
 1204         } else if (d->current_profile != 0x12 &&
 1205                d->current_profile != 0x41 &&
 1206                d->current_profile != 0x43) {
 1207             d->do_stream_recording = 0;
 1208             libdax_msgs_submit(libdax_messenger, d->global_index,
 1209                 0x000201ad,
 1210                 LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
 1211                  "Stream Recording suppressed due to medium type",
 1212                 0, 0);
 1213         }
 1214 
 1215 #endif /* ! Libburn_force_stream_recordinG */
 1216 
 1217     } else if (recmode == -1) {
 1218         d->do_stream_recording = 0;
 1219     }
 1220     if (d->do_stream_recording)
 1221         d->stream_recording_start = start;
 1222     else
 1223         d->stream_recording_start = 0;
 1224     return(1);
 1225 }
 1226 
 1227 void burn_drive_cancel(struct burn_drive *d)
 1228 {
 1229 /* ts B00225 : these mutexes are unnecessary because "= 1" is atomar.
 1230     pthread_mutex_lock(&d->access_lock);
 1231 */
 1232     if (!d->cancel) {
 1233         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 1234                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
 1235                 "burn_drive_cancel() was called", 0, 0);
 1236     }
 1237     d->cancel = 1;
 1238 /*
 1239     pthread_mutex_unlock(&d->access_lock);
 1240 */
 1241 }
 1242 
 1243 
 1244 static void strip_spaces(char *str, size_t len)
 1245 {
 1246     char *tmp, *tmp2;
 1247 
 1248     /* Remove trailing blanks */
 1249     for (tmp = str + len - 1; tmp >= str && (isspace(*tmp) || !*tmp); tmp--)
 1250         *tmp = 0;
 1251     /* Condense remaining blank intervals to single blanks */
 1252     for (tmp = str; tmp < str + len - 1 && *tmp; tmp++) {
 1253         if (isspace(*tmp) && isspace(*(tmp + 1))) {
 1254             for (tmp2 = tmp + 1; tmp2 < str + len && *tmp2; tmp2++)
 1255                 *(tmp2 - 1) = *tmp2;
 1256             *(tmp2 - 1) = '\0';
 1257             tmp--; /* try same first blank again */
 1258         }
 1259     }
 1260 }
 1261 
 1262 static int drive_getcaps(struct burn_drive *d, struct burn_drive_info *out)
 1263 {
 1264     struct burn_scsi_inquiry_data *id;
 1265     int i, profile;
 1266     struct burn_feature_descr *feat;
 1267 
 1268     /* ts A61007 : now prevented in enumerate_common() */
 1269 #if 0
 1270     a ssert(d->idata);
 1271     a ssert(d->mdata);
 1272 #endif
 1273 
 1274     if(d->idata->valid <= 0)
 1275         return 0;
 1276 
 1277     id = (struct burn_scsi_inquiry_data *)d->idata;
 1278 
 1279     memcpy(out->vendor, id->vendor, sizeof(id->vendor));
 1280     strip_spaces(out->vendor, sizeof(id->vendor));
 1281     memcpy(out->product, id->product, sizeof(id->product));
 1282     strip_spaces(out->product, sizeof(id->product));
 1283     memcpy(out->revision, id->revision, sizeof(id->revision));
 1284     strip_spaces(out->revision, sizeof(id->revision));
 1285     strncpy(out->location, d->devname, 16);
 1286     out->location[16] = '\0';
 1287 
 1288     if (d->mdata->p2a_valid > 0) {
 1289         out->buffer_size = d->mdata->buffer_size;
 1290         out->read_dvdram = !!d->mdata->dvdram_read;
 1291         out->read_dvdr = !!d->mdata->dvdr_read;
 1292         out->read_dvdrom = !!d->mdata->dvdrom_read;
 1293         out->read_cdr = !!d->mdata->cdr_read;
 1294         out->read_cdrw = !!d->mdata->cdrw_read;
 1295         out->write_dvdram = !!d->mdata->dvdram_write;
 1296         out->write_dvdr = !!d->mdata->dvdr_write;
 1297         out->write_cdr = !!d->mdata->cdr_write;
 1298         out->write_cdrw = !!d->mdata->cdrw_write;
 1299         out->write_simulate = !!d->mdata->simulate;
 1300         out->c2_errors = !!d->mdata->c2_pointers;
 1301     } else {
 1302         out->buffer_size = out->read_dvdram = out->read_dvdr = 0;
 1303         out->read_dvdrom = out->read_cdr = out->read_cdrw = 0;
 1304         out->write_dvdram = out->write_dvdr = out->write_cdr = 0;
 1305         out->write_cdrw = out->write_simulate = out->c2_errors = 0;
 1306         for (i = 0; i < d->num_profiles; i++) {
 1307             profile = (d->all_profiles[i * 4] << 8) |
 1308                         d->all_profiles[i * 4 + 1];
 1309             if (profile == 0x09)
 1310                 out->write_cdr = out->read_cdr = 1;
 1311             else if (profile == 0x0a)
 1312                 out->write_cdrw = out->read_cdrw = 1;
 1313             else if (profile == 0x10)
 1314                 out->read_dvdrom = 1;
 1315             else if (profile == 0x11)
 1316                 out->write_dvdr = out->read_dvdr = 1;
 1317             else if (profile == 0x12)
 1318                 out->write_dvdram = out->read_dvdram = 1;
 1319         }
 1320 
 1321         /* Test Write bit of CD TAO, CD Mastering, DVD-R/-RW Write */
 1322         for (i = 0x002D; i <= 0x002F; i++)
 1323             if (burn_drive_has_feature(d, i, &feat, 0))
 1324                 if (feat->data_lenght > 0)
 1325                     out->write_simulate |=
 1326                              !!(feat->data[0] & 4);
 1327     }
 1328 
 1329     out->drive = d;
 1330 
 1331 #ifdef Libburn_dummy_probe_write_modeS
 1332 
 1333     /* ts A91112 */
 1334     /* Set default block types. The call d->probe_write_modes() is quite
 1335        obtrusive. It may be performed explicitly by new API call
 1336              burn_drive_probe_cd_write_modes().
 1337     */
 1338     if (out->write_dvdram || out->write_dvdr ||
 1339         out->write_cdrw || out->write_cdr) {
 1340         out->tao_block_types = d->block_types[BURN_WRITE_TAO] =
 1341                     BURN_BLOCK_MODE1 | BURN_BLOCK_RAW0;
 1342         out->sao_block_types = d->block_types[BURN_WRITE_SAO] =
 1343                     BURN_BLOCK_SAO;
 1344     } else {
 1345         out->tao_block_types = d->block_types[BURN_WRITE_TAO] = 0;
 1346         out->sao_block_types = d->block_types[BURN_WRITE_SAO] = 0;
 1347     }
 1348     out->raw_block_types = d->block_types[BURN_WRITE_RAW] = 0;
 1349     out->packet_block_types = 0;
 1350 
 1351 #else /* Libburn_dummy_probe_write_modeS */
 1352 
 1353     /* update available block types for burners */
 1354     if (out->write_dvdram || out->write_dvdr ||
 1355         out->write_cdrw || out->write_cdr)
 1356         d->probe_write_modes(d);
 1357     out->tao_block_types = d->block_types[BURN_WRITE_TAO];
 1358     out->sao_block_types = d->block_types[BURN_WRITE_SAO];
 1359     out->raw_block_types = d->block_types[BURN_WRITE_RAW];
 1360     out->packet_block_types = d->block_types[BURN_WRITE_PACKET];
 1361 
 1362 #endif /* ! Libburn_dummy_probe_write_modeS */
 1363 
 1364     return 1;
 1365 }
 1366 
 1367 
 1368 
 1369 /* ts A91112 - B00114 API */
 1370 /* Probe available CD write modes and block types.
 1371 */
 1372 int burn_drive_probe_cd_write_modes(struct burn_drive_info *dinfo)
 1373 {
 1374     struct burn_drive *d = dinfo->drive;
 1375 
 1376     if (d == NULL)
 1377         return 0;
 1378     if (dinfo->write_dvdram || dinfo->write_dvdr ||
 1379         dinfo->write_cdrw || dinfo->write_cdr)
 1380         d->probe_write_modes(d);
 1381     dinfo->tao_block_types = d->block_types[BURN_WRITE_TAO];
 1382     dinfo->sao_block_types = d->block_types[BURN_WRITE_SAO];
 1383     dinfo->raw_block_types = d->block_types[BURN_WRITE_RAW];
 1384     dinfo->packet_block_types = d->block_types[BURN_WRITE_PACKET];
 1385     return 1;
 1386 }
 1387 
 1388 
 1389 /* ts A70907 : added parameter flag */
 1390 /* @param flag bit0= reset global drive list */
 1391 int burn_drive_scan_sync(struct burn_drive_info *drives[],
 1392              unsigned int *n_drives, int flag)
 1393 {
 1394     /* ts A70907 :
 1395        There seems to have been a misunderstanding about the role of
 1396        burn_drive_scan_sync(). It needs no static state because it
 1397        is only started once during an asynchronous scan operation.
 1398        Its starter, burn_drive_scan(), is the one which ends immediately
 1399        and gets called repeatedly. It acts on start of scanning by
 1400        calling burn_drive_scan_sync(), returns idle while scanning is
 1401        not done and finally removes the worker object which represented
 1402        burn_drive_scan_sync().
 1403        The scanning itself is not parallel but enumerates sequentially
 1404        drive by drive (within scsi_enumerate_drives()).
 1405 
 1406        I will use "scanned" for marking drives found by previous runs.
 1407            It will not be static any more.
 1408     */
 1409     /* ts A71015 : this makes only trouble : static int scanning = 0; */
 1410     /* ts A70907 :
 1411        These variables are too small anyway. We got up to 255 drives.
 1412        static int scanned = 0, found = 0;
 1413        Variable "found" was only set but never read.
 1414     */
 1415     unsigned char scanned[32];
 1416     unsigned count = 0;
 1417     int i, ret;
 1418 
 1419     /* ts A61007 : moved up to burn_drive_scan() */
 1420     /* a ssert(burn_running); */
 1421 
 1422 
 1423     /* ts A61007 : test moved up to burn_drive_scan()
 1424                        burn_wait_all() is obsoleted */
 1425 #if 0
 1426     /* make sure the drives aren't in use */
 1427     burn_wait_all();    /* make sure the queue cleans up
 1428                    before checking for the released
 1429                    state */
 1430 #endif /* 0 */
 1431 
 1432     *n_drives = 0;
 1433 
 1434     /* ts A70907 : whether to scan from scratch or to extend */
 1435     for (i = 0; i < (int) sizeof(scanned); i++)
 1436         scanned[i] = 0;
 1437     if (flag & 1) {
 1438         burn_drive_free_all();
 1439     } else {
 1440         for (i = 0; i <= drivetop; i++) 
 1441             if (drive_array[i].global_index >= 0)
 1442                 scanned[i / 8] |=  (1 << (i % 8));
 1443     }
 1444 
 1445     /* refresh the lib's drives */
 1446 
 1447     /* ts A61115 : formerly sg_enumerate(); ata_enumerate(); */
 1448     scsi_enumerate_drives();
 1449 
 1450     count = burn_drive_count();
 1451     if (count) {
 1452         /* ts A70907 :
 1453            Extra array element marks end of array. */
 1454         *drives = calloc(count + 1,
 1455                 sizeof(struct burn_drive_info));
 1456         if (*drives == NULL) {
 1457                 libdax_msgs_submit(libdax_messenger, -1, 0x00000003,
 1458                             LIBDAX_MSGS_SEV_FATAL,
 1459                     LIBDAX_MSGS_PRIO_HIGH,
 1460                     "Out of virtual memory", 0, 0);
 1461             return -1;
 1462         } else
 1463             for (i = 0; i <= (int) count; i++) /* invalidate */
 1464                 (*drives)[i].drive = NULL;
 1465     } else
 1466         *drives = NULL;
 1467 
 1468     for (i = 0; i < (int) count; ++i) {
 1469         if (scanned[i / 8] & (1 << (i % 8)))
 1470     continue;       /* device already scanned by previous run */
 1471         if (drive_array[i].global_index < 0)
 1472     continue;       /* invalid device */
 1473 
 1474         /* ts A90602 : This old loop is not plausible. See A70907.
 1475           while (!drive_getcaps(&drive_array[i],
 1476                  &(*drives)[*n_drives])) {
 1477             sleep(1);
 1478           }
 1479         */
 1480         /* ts A90602 : A single call shall do (rather than a loop) */
 1481         ret = drive_getcaps(&drive_array[i], &(*drives)[*n_drives]);
 1482         if (ret > 0)
 1483             (*n_drives)++;
 1484         scanned[i / 8] |= 1 << (i % 8);
 1485     }
 1486     if (*drives != NULL && *n_drives == 0) {
 1487         free ((char *) *drives);
 1488         *drives = NULL;
 1489     }
 1490 
 1491     return(1);
 1492 }
 1493 
 1494 /* ts A61001 : internal call */
 1495 int burn_drive_forget(struct burn_drive *d, int force)
 1496 {
 1497     int occup;
 1498 
 1499     occup = burn_drive_is_occupied(d);
 1500 /*
 1501     fprintf(stderr, "libburn: experimental: occup == %d\n",occup);
 1502 */
 1503     if(occup <= -2)
 1504         return 2;
 1505     if(occup > 0)
 1506         if(force < 1)
 1507             return 0; 
 1508     if(occup >= 10)
 1509         return 0;
 1510 
 1511     /* >>> do any drive calming here */;
 1512 
 1513 
 1514     burn_drive_force_idle(d);
 1515     if(occup > 0 && !burn_drive_is_released(d))
 1516         burn_drive_release(d,0);
 1517     burn_drive_free(d);
 1518     return 1;
 1519 }
 1520 
 1521 /* API call */
 1522 int burn_drive_info_forget(struct burn_drive_info *info, int force)
 1523 {
 1524     return burn_drive_forget(info->drive, force);
 1525 }
 1526 
 1527 
 1528 void burn_drive_info_free(struct burn_drive_info drive_infos[])
 1529 {
 1530 #ifndef Libburn_free_all_drives_on_infO
 1531     int i;
 1532 #endif
 1533 
 1534 /* ts A60904 : ticket 62, contribution by elmom */
 1535 /* clarifying the meaning and the identity of the victim */
 1536 
 1537     if(drive_infos == NULL)
 1538         return;
 1539 
 1540 #ifndef Libburn_free_all_drives_on_infO
 1541 
 1542 #ifdef Not_yeT
 1543     int new_drivetop;
 1544 
 1545     /* ts A71015: compute reduced drivetop counter */
 1546     new_drivetop = drivetop;
 1547     for (i = 0; drive_infos[i].drive != NULL; i++)
 1548         if (drive_infos[i].global_index == new_drivetop
 1549             && new_drivetop >= 0) {
 1550             new_drivetop--;
 1551             i = 0;
 1552         }
 1553 #endif /* Not_yeT */
 1554 
 1555     /* ts A70907 : Solution for wrong behavior below */
 1556     for (i = 0; drive_infos[i].drive != NULL; i++)
 1557         burn_drive_free(drive_infos[i].drive);
 1558 
 1559 #ifdef Not_yeT
 1560     drivetop = new_drivetop;
 1561 #endif /* Not_yeT */
 1562 
 1563 #endif /* ! Libburn_free_all_drives_on_infO */
 1564 
 1565     /* ts A60904 : This looks a bit weird. [ts A70907 : not any more]
 1566        burn_drive_info is not the manager of burn_drive but only its
 1567        spokesperson. To my knowledge drive_infos from burn_drive_scan()
 1568        are not memorized globally. */
 1569     free((void *) drive_infos);
 1570 
 1571 #ifdef Libburn_free_all_drives_on_infO
 1572     /* ts A70903 : THIS IS WRONG !      (disabled now)
 1573        It endangers multi drive usage.
 1574        This call is not entitled to delete all drives, only the
 1575        ones of the array which it receives a parameter.
 1576 
 1577        Problem:  It was unclear how many items are listed in drive_infos
 1578            Solution: Added a end marker element to any burn_drive_info array 
 1579                      The mark can be recognized by having drive == NULL
 1580     */
 1581     burn_drive_free_all();
 1582 #endif
 1583 }
 1584 
 1585 
 1586 struct burn_disc *burn_drive_get_disc(struct burn_drive *d)
 1587 {
 1588     /* ts A61022: SIGSEGV on calling this function with blank media */
 1589     if(d->disc == NULL)
 1590         return NULL;
 1591 
 1592     d->disc->refcnt++;
 1593     return d->disc;
 1594 }
 1595 
 1596 void burn_drive_set_speed(struct burn_drive *d, int r, int w)
 1597 {
 1598     d->nominal_write_speed = w;
 1599     if(d->drive_role != 1)
 1600         return;
 1601     d->set_speed(d, r, w);
 1602 }
 1603 
 1604 int burn_drive_set_speed_exact(struct burn_drive *d, int r, int w)
 1605 {
 1606     int sose;
 1607 
 1608     d->nominal_write_speed = w;
 1609     if(d->drive_role != 1)
 1610         return 0;
 1611     sose = d->silent_on_scsi_error;
 1612     d->silent_on_scsi_error = 3;
 1613     d->set_streaming_err = 0;
 1614     d->set_streaming_exact_bit = 1;
 1615     d->set_speed(d, r, w);
 1616     d->silent_on_scsi_error = sose;
 1617     d->set_streaming_exact_bit = 0;
 1618     return !d->set_streaming_err;
 1619 }
 1620 
 1621 /* ts A70711  API function */
 1622 int burn_drive_set_buffer_waiting(struct burn_drive *d, int enable,
 1623                 int min_usec, int max_usec, int timeout_sec,
 1624                 int min_percent, int max_percent)
 1625 {
 1626 
 1627     if (enable >= 0)
 1628         d->wait_for_buffer_free = !!enable;
 1629     if (min_usec >= 0)
 1630         d->wfb_min_usec = min_usec;
 1631     if (max_usec >= 0)
 1632         d->wfb_max_usec = max_usec;
 1633     if (timeout_sec >= 0)
 1634         d->wfb_timeout_sec = timeout_sec;
 1635         if (min_percent >= 0) {
 1636         if (min_percent < 25 || min_percent > 100)
 1637             return 0;
 1638         d->wfb_min_percent = min_percent;
 1639     }
 1640     if (max_percent >= 0) {
 1641         if (max_percent < 25 || max_percent > 100)
 1642             return 0;
 1643         d->wfb_max_percent = max_percent;
 1644     }
 1645     return 1;
 1646 }
 1647 
 1648 
 1649 int burn_drive_reset_simulate(struct burn_drive *d, int simulate)
 1650 {
 1651     if (d->busy != BURN_DRIVE_IDLE) {
 1652         libdax_msgs_submit(libdax_messenger,
 1653             d->global_index, 0x00020140,
 1654             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 1655             "Drive is busy on attempt to write random access",0,0);
 1656         return 0;
 1657     }
 1658     d->do_simulate = !!simulate;
 1659     return 1;
 1660 }
 1661 
 1662 
 1663 int burn_msf_to_sectors(int m, int s, int f)
 1664 {
 1665     return (m * 60 + s) * 75 + f;
 1666 }
 1667 
 1668 void burn_sectors_to_msf(int sectors, int *m, int *s, int *f)
 1669 {
 1670     *m = sectors / (60 * 75);
 1671     *s = (sectors - *m * 60 * 75) / 75;
 1672     *f = sectors - *m * 60 * 75 - *s * 75;
 1673 }
 1674 
 1675 int burn_drive_get_read_speed(struct burn_drive *d)
 1676 {
 1677     return d->mdata->max_read_speed;
 1678 }
 1679 
 1680 int burn_drive_get_write_speed(struct burn_drive *d)
 1681 {
 1682     return d->mdata->max_write_speed;
 1683 }
 1684 
 1685 /* ts A61021 : New API function */
 1686 int burn_drive_get_min_write_speed(struct burn_drive *d)
 1687 {
 1688     return d->mdata->min_write_speed;
 1689 }
 1690 
 1691 
 1692 /* ts A51221 */
 1693 static char *enumeration_whitelist[BURN_DRIVE_WHITELIST_LEN];
 1694 static int enumeration_whitelist_top = -1;
 1695 
 1696 /** Add a device to the list of permissible drives. As soon as some entry is in
 1697     the whitelist all non-listed drives are banned from enumeration.
 1698     @return 1 success, <=0 failure
 1699 */
 1700 int burn_drive_add_whitelist(char *device_address)
 1701 {
 1702     char *new_item;
 1703     if(enumeration_whitelist_top+1 >= BURN_DRIVE_WHITELIST_LEN)
 1704         return 0;
 1705     enumeration_whitelist_top++;
 1706     new_item = calloc(1, strlen(device_address) + 1);
 1707     if (new_item == NULL)
 1708         return -1;
 1709     strcpy(new_item, device_address);
 1710     enumeration_whitelist[enumeration_whitelist_top] = new_item;
 1711     return 1;
 1712 }
 1713 
 1714 /** Remove all drives from whitelist. This enables all possible drives. */
 1715 void burn_drive_clear_whitelist(void)
 1716 {
 1717     int i;
 1718     for (i = 0; i <= enumeration_whitelist_top; i++)
 1719         free(enumeration_whitelist[i]);
 1720     enumeration_whitelist_top = -1;
 1721 }
 1722 
 1723 int burn_drive_is_banned(char *device_address)
 1724 {
 1725     int i;
 1726     if(enumeration_whitelist_top<0)
 1727         return 0;
 1728     for (i = 0; i <= enumeration_whitelist_top; i++) 
 1729         if (strcmp(enumeration_whitelist[i], device_address) == 0)
 1730             return 0;
 1731     return 1;
 1732 }
 1733 
 1734 
 1735 /* ts A80731 */
 1736 int burn_drive_whitelist_count(void)
 1737 {
 1738     return enumeration_whitelist_top + 1;
 1739 }
 1740 
 1741 char *burn_drive_whitelist_item(int idx, int flag)
 1742 {
 1743     if (idx < 0 || idx > enumeration_whitelist_top)
 1744         return NULL;
 1745     return enumeration_whitelist[idx];
 1746 }
 1747 
 1748 
 1749 static int burn_role_by_access(char *fname, int flag)
 1750 {
 1751 /* We normally need _LARGEFILE64_SOURCE defined by the build system.
 1752    Nevertheless the system might use large address integers by default.
 1753 */
 1754 #ifndef O_LARGEFILE
 1755 #define O_LARGEFILE 0
 1756 #endif
 1757     int fd;
 1758         
 1759     fd = open(fname, O_RDWR | O_LARGEFILE | O_BINARY);
 1760     if (fd != -1) {
 1761         close(fd);
 1762         return 2;
 1763     }
 1764     fd = open(fname, O_RDONLY | O_LARGEFILE | O_BINARY);
 1765         if (fd != -1) {
 1766         close(fd);
 1767         return 4;
 1768     }
 1769     fd = open(fname, O_WRONLY | O_LARGEFILE | O_BINARY);
 1770     if (fd != -1) {
 1771         close(fd);
 1772         return 5;
 1773     }
 1774     if (flag & 1)
 1775         return 0;
 1776     return 2;
 1777 }
 1778 
 1779 
 1780 /* ts A70903 : Implements adquiration of pseudo drives */
 1781 int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname)
 1782 {
 1783     int ret = -1, role = 0, fd;
 1784     int is_rdwr = 0, stat_ret = -1;
 1785     /* divided by 512 it needs to fit into a signed long integer */
 1786     off_t size = ((off_t) (512 * 1024 * 1024 - 1) * (off_t) 2048);
 1787     off_t read_size = -1;
 1788     struct burn_drive *d= NULL, *regd_d;
 1789     struct stat stbuf;
 1790 
 1791     if (fname[0] != 0) {
 1792         fd = burn_drive__fd_from_special_adr(fname);
 1793         is_rdwr = burn_drive__is_rdwr(fname, &stat_ret, &stbuf,
 1794                         &read_size, 1 | 2);
 1795         if (stat_ret == -1 || is_rdwr) {
 1796             ret = burn_os_stdio_capacity(fname, 0, &size);
 1797             if (ret == -1) {
 1798                 libdax_msgs_submit(libdax_messenger, -1,
 1799                  0x00020009,
 1800                  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1801                  "Neither stdio-path nor its directory exist",
 1802                  0, 0);
 1803                 return 0;
 1804             } else if (ret == -2) {
 1805                 libdax_msgs_submit(libdax_messenger, -1,
 1806                 0x00020005,
 1807                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1808                 "Failed to open device (a pseudo-drive)",
 1809                 errno, 0);
 1810                 return 0;
 1811             }
 1812             if (fname[0] != 0) {
 1813                 if (is_rdwr == 2 &&
 1814                     (burn_drive_role_4_allowed & 1))
 1815                     role = 4;
 1816                 else if (is_rdwr == 3 &&
 1817                     (burn_drive_role_4_allowed & 1))
 1818                     role = 5;
 1819                 else
 1820                     role = 2;
 1821                 if (stat_ret != -1 && role == 2 && fd == -1 &&
 1822                     (burn_drive_role_4_allowed & 3) == 3)
 1823                     role = burn_role_by_access(fname,
 1824                         !!(burn_drive_role_4_allowed & 4));
 1825             } else
 1826                 role = 0;
 1827         } else {
 1828             role = 3;
 1829         }
 1830     }
 1831     d= (struct burn_drive *) calloc(1, sizeof(struct burn_drive));
 1832     if (d == NULL)
 1833         return 0;
 1834     burn_setup_drive(d, fname);
 1835     d->status = BURN_DISC_EMPTY;
 1836 
 1837     d->drive_role = role;
 1838     ret = burn_scsi_setup_drive(d, -1, -1, -1, -1, -1, 0);
 1839     if (ret <= 0)
 1840         goto ex;
 1841     regd_d = burn_drive_register(d);
 1842     if (regd_d == NULL) {
 1843         ret = -1;
 1844         goto ex;
 1845     }
 1846     free((char *) d); /* all sub pointers have been copied to *regd_d */
 1847     d = regd_d;
 1848     if (d->drive_role >= 2 && d->drive_role <= 5) {
 1849         if (d->drive_role == 4) {
 1850             if (read_size > 0)
 1851                 d->status = BURN_DISC_FULL;
 1852             else
 1853                 d->status = BURN_DISC_EMPTY;
 1854             d->block_types[BURN_WRITE_TAO] = 0;
 1855             d->block_types[BURN_WRITE_SAO] = 0;
 1856         } else {
 1857             if (d->drive_role == 5 && stat_ret != -1 &&
 1858                 S_ISREG(stbuf.st_mode) && stbuf.st_size > 0 &&
 1859                 (burn_drive_role_4_allowed & 8)) {
 1860                 d->status = BURN_DISC_APPENDABLE;
 1861                 d->block_types[BURN_WRITE_SAO] = 0;
 1862                 if (stbuf.st_size / (off_t) 2048
 1863                     >= 0x7ffffff0) {
 1864                     d->status = BURN_DISC_FULL;
 1865                     d->role_5_nwa = 0x7ffffff0;
 1866                 } else 
 1867                     d->role_5_nwa = stbuf.st_size / 2048 +
 1868                                   !!(stbuf.st_size % 2048);
 1869             } else {
 1870                 d->status = BURN_DISC_BLANK;
 1871                 d->block_types[BURN_WRITE_SAO] =
 1872                                 BURN_BLOCK_SAO;
 1873                 d->role_5_nwa = 0;
 1874             }
 1875             d->block_types[BURN_WRITE_TAO] = BURN_BLOCK_MODE1;
 1876         }
 1877         d->current_profile = 0xffff; /* MMC for non-compliant drive */
 1878         strcpy(d->current_profile_text,"stdio file");
 1879         d->current_is_cd_profile = 0;
 1880         d->current_is_supported_profile = 1;
 1881         if (read_size >= 0) {
 1882             /* despite its name : last valid address, not size */
 1883             d->media_read_capacity =
 1884                 read_size / 2048 - !(read_size % 2048);
 1885             d->mr_capacity_trusted = 1;
 1886         }
 1887         burn_drive_set_media_capacity_remaining(d, size);
 1888     } else
 1889         d->current_profile = 0; /* Drives return this if empty */
 1890 
 1891     *drive_infos = calloc(2, sizeof(struct burn_drive_info));
 1892     if (*drive_infos == NULL)
 1893         goto ex;
 1894     (*drive_infos)[0].drive = d;
 1895     (*drive_infos)[1].drive = NULL; /* End-Of-List mark */
 1896     (*drive_infos)[0].tao_block_types = d->block_types[BURN_WRITE_TAO];
 1897     (*drive_infos)[0].sao_block_types = d->block_types[BURN_WRITE_SAO];
 1898     if (d->drive_role == 2) {
 1899         strcpy((*drive_infos)[0].vendor,"YOYODYNE");
 1900         strcpy((*drive_infos)[0].product,"WARP DRIVE");
 1901         strcpy((*drive_infos)[0].revision,"FX01");
 1902     } else if (d->drive_role == 3) {
 1903         strcpy((*drive_infos)[0].vendor,"YOYODYNE");
 1904         strcpy((*drive_infos)[0].product,"BLACKHOLE");
 1905         strcpy((*drive_infos)[0].revision,"FX02");
 1906     } else if (d->drive_role == 4) {
 1907         strcpy((*drive_infos)[0].vendor,"YOYODYNE");
 1908         strcpy((*drive_infos)[0].product,"WARP DRIVE");
 1909         strcpy((*drive_infos)[0].revision,"FX03");
 1910     } else if (d->drive_role == 5) {
 1911         strcpy((*drive_infos)[0].vendor,"YOYODYNE");
 1912         strcpy((*drive_infos)[0].product,"WARP DRIVE");
 1913         strcpy((*drive_infos)[0].revision,"FX04");
 1914     } else {
 1915         strcpy((*drive_infos)[0].vendor,"FERENGI");
 1916         strcpy((*drive_infos)[0].product,"VAPORWARE");
 1917         strcpy((*drive_infos)[0].revision,"0000");
 1918     }
 1919     d->released = 0;
 1920     ret = 1;
 1921 ex:;
 1922     if (ret <= 0 && d != NULL) {
 1923         burn_drive_free_subs(d);
 1924         free((char *) d);
 1925     }
 1926     return ret;
 1927 }
 1928 
 1929 
 1930 /* ts A60823 */
 1931 /** Acquire a drive with known persistent address. 
 1932 */
 1933 int burn_drive_scan_and_grab(struct burn_drive_info *drive_infos[], char* adr,
 1934                  int load)
 1935 {
 1936     unsigned int n_drives;
 1937     int ret, i;
 1938 
 1939     /* check whether drive address is already registered */
 1940     for (i = 0; i <= drivetop; i++)
 1941         if (drive_array[i].global_index >= 0)
 1942             if (strcmp(drive_array[i].devname, adr) == 0)
 1943     break;
 1944     if (i <= drivetop) {
 1945         libdax_msgs_submit(libdax_messenger, i,
 1946                 0x0002014b,
 1947                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1948                 "Drive is already registered resp. scanned",
 1949                 0, 0);
 1950         return -1;
 1951     }
 1952 
 1953     if (strncmp(adr, "stdio:", 6) == 0) {
 1954         ret = burn_drive_grab_dummy(drive_infos, adr + 6);
 1955         return ret;
 1956     }
 1957 
 1958     burn_drive_clear_whitelist();
 1959     burn_drive_add_whitelist(adr);
 1960 /*
 1961     fprintf(stderr,"libburn: experimental: burn_drive_scan_and_grab(%s)\n",
 1962         adr);
 1963 */
 1964 
 1965     /* ts A70907 : now calling synchronously rather than looping */
 1966     ret = burn_drive_scan_sync(drive_infos, &n_drives, 0);
 1967     if (ret < 0)
 1968         return -1;
 1969 
 1970     if (n_drives == 0)
 1971         return 0;
 1972 /*
 1973     fprintf(stderr, "libburn: experimental: n_drives %d , drivetop %d\n",
 1974         n_drives, drivetop);
 1975     if (n_drives > 0)
 1976         fprintf(stderr, "libburn: experimental: global_index %d\n",
 1977             drive_infos[0]->drive->global_index);
 1978 */
 1979 
 1980     ret = burn_drive_grab(drive_infos[0]->drive, load);
 1981     if (ret != 1) {
 1982         burn_drive_forget(drive_infos[0]->drive, 0);
 1983         return -1;
 1984     }
 1985     return 1;
 1986 }
 1987 
 1988 /* ts A60925 */
 1989 /** Simple debug message frontend to libdax_msgs_submit().
 1990     If arg is not NULL, then fmt MUST contain exactly one %s and no
 1991     other sprintf() %-formatters.
 1992 */
 1993 int burn_drive_adr_debug_msg(char *fmt, char *arg)
 1994 {
 1995     int ret;
 1996     char *msg = NULL, *msgpt;
 1997 
 1998     if(libdax_messenger == NULL)
 1999         return 0;
 2000     if(arg != NULL) {
 2001         BURN_ALLOC_MEM(msg, char, 4096);
 2002         msgpt = msg;
 2003         sprintf(msg, fmt, arg);
 2004     } else {
 2005         msgpt = fmt;
 2006     }
 2007     ret = libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 2008                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
 2009                 msgpt, 0, 0);
 2010 ex:;
 2011     BURN_FREE_MEM(msg);
 2012     return ret;
 2013 }
 2014 
 2015 /* ts A60923 */ /* ts A70906 : promoted to API */
 2016 /** Inquire the persistent address of the given drive. */
 2017 int burn_drive_d_get_adr(struct burn_drive *d, char adr[])
 2018 {
 2019     if (strlen(d->devname) >= BURN_DRIVE_ADR_LEN) {
 2020         libdax_msgs_submit(libdax_messenger, d->global_index,
 2021                 0x00020110,
 2022                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2023                 "Persistent drive address too long", 0, 0);
 2024         return -1;
 2025     }
 2026     strcpy(adr,d->devname);
 2027     return 1;
 2028 }
 2029 
 2030 /* ts A60823 - A60923 */ /* A70906 : Now legacy API call */
 2031 /** Inquire the persistent address of the given drive. */
 2032 int burn_drive_get_adr(struct burn_drive_info *drive_info, char adr[])
 2033 {
 2034     int ret;
 2035 
 2036     ret = burn_drive_d_get_adr(drive_info->drive, adr);
 2037     return ret;
 2038 }
 2039 
 2040 
 2041 
 2042 
 2043 /* ts A60922 ticket 33 */
 2044 /** Evaluate whether the given address would be enumerated by libburn */
 2045 int burn_drive_is_enumerable_adr(char *adr)
 2046 {
 2047     return sg_is_enumerable_adr(adr);
 2048 }
 2049 
 2050 #define BURN_DRIVE_MAX_LINK_DEPTH 20
 2051 
 2052 /* ts A60922 ticket 33 */
 2053 /* @param flag  bit0= no debug messages
 2054                 bit1= resolve only links,
 2055                       do not rely on drive list for resolving via st_rdev
 2056 */
 2057 int burn_drive_resolve_link(char *path, char adr[], int *recursion_count,
 2058                 int flag)
 2059 {
 2060     int ret, link_target_size = 4096;
 2061     char *link_target = NULL, *msg = NULL, *link_adr = NULL, *adrpt;
 2062     struct stat stbuf;
 2063 
 2064     BURN_ALLOC_MEM(link_target, char, link_target_size);
 2065     BURN_ALLOC_MEM(msg, char, link_target_size + 100);
 2066     BURN_ALLOC_MEM(link_adr, char, link_target_size);
 2067 
 2068     if (flag & 1)
 2069         burn_drive_adr_debug_msg("burn_drive_resolve_link( %s )",
 2070                                     path);
 2071     if (*recursion_count >= BURN_DRIVE_MAX_LINK_DEPTH) {
 2072         if (flag & 1)
 2073             burn_drive_adr_debug_msg(
 2074             "burn_drive_resolve_link aborts because link too deep",
 2075             NULL);
 2076         {ret = 0; goto ex;}
 2077     }
 2078     (*recursion_count)++;
 2079     ret = readlink(path, link_target, link_target_size);
 2080     if (ret == -1) {
 2081         if (flag & 1)
 2082             burn_drive_adr_debug_msg("readlink( %s ) returns -1",
 2083                                     path);
 2084         {ret = 0; goto ex;}
 2085     }
 2086     if (ret >= link_target_size - 1) {
 2087         sprintf(msg,"readlink( %s ) returns %d (too much)", path, ret);
 2088         if (flag & 1)
 2089             burn_drive_adr_debug_msg(msg, NULL);
 2090         {ret = -1; goto ex;}
 2091     }
 2092     link_target[ret] = 0;
 2093     adrpt = link_target;
 2094     if (link_target[0] != '/') {
 2095         strcpy(link_adr, path);
 2096         if ((adrpt = strrchr(link_adr, '/')) != NULL) {
 2097             strcpy(adrpt + 1, link_target);
 2098             adrpt = link_adr;
 2099         } else
 2100             adrpt = link_target;
 2101     }
 2102     if (flag & 2) {
 2103         /* Link-only recursion */
 2104         if (lstat(adrpt, &stbuf) == -1) {
 2105             ;
 2106         } else if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
 2107             ret = burn_drive_resolve_link(adrpt, adr,
 2108                          recursion_count, flag);
 2109         } else {
 2110             strcpy(adr, adrpt);
 2111         }
 2112     } else {
 2113         /* Link and device number recursion */
 2114         ret = burn_drive_convert_fs_adr_sub(adrpt, adr,
 2115                             recursion_count);
 2116         sprintf(msg,"burn_drive_convert_fs_adr( %s ) returns %d",
 2117             link_target, ret);
 2118     }
 2119     if (flag & 1)
 2120         burn_drive_adr_debug_msg(msg, NULL);
 2121 ex:;
 2122     BURN_FREE_MEM(link_target);
 2123     BURN_FREE_MEM(msg);
 2124     BURN_FREE_MEM(link_adr);
 2125     return ret;
 2126 }
 2127 
 2128 /* ts A60922 - A61014 ticket 33 */
 2129 /* Try to find an enumerated address with the given stat.st_rdev number */
 2130 int burn_drive_find_devno(dev_t devno, char adr[])
 2131 {
 2132     char *fname = NULL, *msg = NULL;
 2133     int ret = 0, first = 1, fname_size = 4096;
 2134     struct stat stbuf;
 2135     burn_drive_enumerator_t enm;
 2136 
 2137     BURN_ALLOC_MEM(fname, char, fname_size);
 2138     BURN_ALLOC_MEM(msg, char, fname_size + 100);
 2139 
 2140     while (1) {
 2141         ret = sg_give_next_adr(&enm, fname, fname_size, first);
 2142         if(ret <= 0)
 2143     break;
 2144         first = 0;
 2145         ret = stat(fname, &stbuf);
 2146         if(ret == -1)
 2147     continue;
 2148         if(devno != stbuf.st_rdev)
 2149     continue;
 2150         if(strlen(fname) >= BURN_DRIVE_ADR_LEN)
 2151             {ret= -1; goto ex;}
 2152 
 2153         sprintf(msg, "burn_drive_find_devno( 0x%lX ) found %s",
 2154              (long) devno, fname);
 2155         burn_drive_adr_debug_msg(msg, NULL);
 2156         strcpy(adr, fname);
 2157         { ret = 1; goto ex;}
 2158     }
 2159     ret = 0;
 2160 ex:;
 2161     if (first == 0)
 2162         sg_give_next_adr(&enm, fname, fname_size, -1);
 2163     BURN_FREE_MEM(fname);
 2164     BURN_FREE_MEM(msg);
 2165     return ret;
 2166 }
 2167 
 2168 /* ts A60923 */
 2169 /** Try to obtain host,channel,target,lun from path.
 2170     @return     1 = success , 0 = failure , -1 = severe error
 2171 */
 2172 int burn_drive_obtain_scsi_adr(char *path,
 2173                    int *bus_no, int *host_no, int *channel_no,
 2174                    int *target_no, int *lun_no)
 2175 {
 2176     int ret, i;
 2177     char *adr = NULL;
 2178 
 2179     BURN_ALLOC_MEM(adr, char, BURN_DRIVE_ADR_LEN);
 2180 
 2181     /* open drives cannot be inquired by sg_obtain_scsi_adr() */
 2182     for (i = 0; i < drivetop + 1; i++) {
 2183         if (drive_array[i].global_index < 0)
 2184     continue;
 2185         ret = burn_drive_d_get_adr(&(drive_array[i]),adr);
 2186         if (ret < 0)
 2187             {ret = 1; goto ex;}
 2188         if (ret == 0)
 2189     continue;
 2190         if (strcmp(adr, path) == 0) {
 2191             *host_no = drive_array[i].host;
 2192             *channel_no = drive_array[i].channel;
 2193             *target_no = drive_array[i].id;
 2194             *lun_no = drive_array[i].lun;
 2195             *bus_no = drive_array[i].bus_no;
 2196             if (*host_no < 0 || *channel_no < 0 ||
 2197                 *target_no < 0 || *lun_no < 0)
 2198                 {ret = 0; goto ex;}
 2199             {ret = 1; goto ex;}
 2200         }
 2201     }
 2202 
 2203     ret = sg_obtain_scsi_adr(path, bus_no, host_no, channel_no,
 2204                  target_no, lun_no);
 2205 ex:;
 2206     BURN_FREE_MEM(adr);
 2207     return ret;
 2208 }
 2209 
 2210 /* ts A60923 */
 2211 int burn_drive_convert_scsi_adr(int bus_no, int host_no, int channel_no,
 2212                 int target_no, int lun_no, char adr[])
 2213 {
 2214     char *fname = NULL, *msg = NULL;
 2215     int ret = 0, first = 1, i_bus_no = -1, fname_size = 4096;
 2216     int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
 2217     burn_drive_enumerator_t enm;
 2218 
 2219     BURN_ALLOC_MEM(fname, char, fname_size);
 2220     BURN_ALLOC_MEM(msg, char, fname_size + 100);
 2221 
 2222     sprintf(msg,"burn_drive_convert_scsi_adr( %d,%d,%d,%d,%d )",
 2223         bus_no, host_no, channel_no, target_no, lun_no);
 2224     burn_drive_adr_debug_msg(msg, NULL);
 2225 
 2226     while (1) {
 2227         ret= sg_give_next_adr(&enm, fname, fname_size, first);
 2228         if(ret <= 0)
 2229     break;
 2230         first = 0;
 2231         ret = burn_drive_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
 2232                  &i_channel_no, &i_target_no, &i_lun_no);
 2233         if(ret <= 0)
 2234     continue;
 2235         if(bus_no >=0 && i_bus_no != bus_no)
 2236     continue;
 2237         if(host_no >=0 && i_host_no != host_no)
 2238     continue;
 2239         if(channel_no >= 0 && i_channel_no != channel_no)
 2240     continue;
 2241         if(target_no >= 0 && i_target_no != target_no)
 2242     continue;
 2243         if(lun_no >= 0 && i_lun_no != lun_no)
 2244     continue;
 2245         if(strlen(fname) >= BURN_DRIVE_ADR_LEN)
 2246             { ret = -1; goto ex;}
 2247         burn_drive_adr_debug_msg(
 2248             "burn_drive_convert_scsi_adr() found %s", fname);
 2249         strcpy(adr, fname);
 2250         { ret = 1; goto ex;}
 2251     }
 2252     ret = 0;
 2253 ex:;
 2254     if (first == 0)
 2255         sg_give_next_adr(&enm, fname, fname_size, -1);
 2256     BURN_FREE_MEM(fname);
 2257     BURN_FREE_MEM(msg);
 2258     return ret;
 2259 }
 2260 
 2261 /* ts A60922 ticket 33 */
 2262 /* Try to find an enumerated address with the same host,channel,target,lun
 2263    as path */
 2264 int burn_drive_find_scsi_equiv(char *path, char adr[])
 2265 {
 2266     int ret = 0;
 2267     int bus_no, host_no, channel_no, target_no, lun_no;
 2268     char msg[4096];
 2269 
 2270     ret = burn_drive_obtain_scsi_adr(path, &bus_no, &host_no, &channel_no,
 2271                      &target_no, &lun_no);
 2272     if(ret <= 0) {
 2273         sprintf(msg,"burn_drive_obtain_scsi_adr( %s ) returns %d",
 2274             path, ret);
 2275         burn_drive_adr_debug_msg(msg, NULL);
 2276         return 0;
 2277     }
 2278     sprintf(msg, "burn_drive_find_scsi_equiv( %s ) : (%d),%d,%d,%d,%d",
 2279         path, bus_no, host_no, channel_no, target_no, lun_no);
 2280     burn_drive_adr_debug_msg(msg, NULL);
 2281 
 2282     ret= burn_drive_convert_scsi_adr(-1, host_no, channel_no, target_no,
 2283                      lun_no, adr);
 2284     return ret;
 2285 }
 2286 
 2287 
 2288 /* ts A60922 ticket 33 */
 2289 /** Try to convert a given existing filesystem address into a persistent drive
 2290     address.  */
 2291 int burn_drive_convert_fs_adr_sub(char *path, char adr[], int *rec_count)
 2292 {
 2293     int ret;
 2294     struct stat stbuf;
 2295 
 2296     burn_drive_adr_debug_msg("burn_drive_convert_fs_adr( %s )", path);
 2297     if (strncmp(path, "stdio:", 6) == 0 ||
 2298         burn_drive_is_enumerable_adr(path)) {
 2299         if(strlen(path) >= BURN_DRIVE_ADR_LEN)
 2300             return -1;
 2301         if (strncmp(path, "stdio:", 6) != 0)
 2302             burn_drive_adr_debug_msg(
 2303                "burn_drive_is_enumerable_adr( %s ) is true", path);
 2304         strcpy(adr, path);
 2305         return 1;
 2306     }
 2307 
 2308     if(lstat(path, &stbuf) == -1) {
 2309         burn_drive_adr_debug_msg("lstat( %s ) returns -1", path);
 2310         return 0;
 2311     }
 2312     if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
 2313         ret = burn_drive_resolve_link(path, adr, rec_count, 0);
 2314         if(ret > 0)
 2315             return 1;
 2316         burn_drive_adr_debug_msg("link fallback via stat( %s )", path);
 2317         if(stat(path, &stbuf) == -1) {
 2318             burn_drive_adr_debug_msg("stat( %s ) returns -1",path);
 2319             return 0;
 2320         }
 2321     }
 2322     if((stbuf.st_mode&S_IFMT) == S_IFBLK ||
 2323        (stbuf.st_mode&S_IFMT) == S_IFCHR) {
 2324         ret = burn_drive_find_devno(stbuf.st_rdev, adr);
 2325         if(ret > 0)
 2326             return 1;
 2327         ret = burn_drive_find_scsi_equiv(path, adr);
 2328         if(ret > 0)
 2329             return 1;
 2330     }
 2331     burn_drive_adr_debug_msg("Nothing found for %s", path);
 2332     return 0;
 2333 }
 2334 
 2335 /* API */
 2336 /** Try to convert a given existing filesystem address into a persistent drive
 2337     address.  */
 2338 int burn_drive_convert_fs_adr(char *path, char adr[])
 2339 {
 2340     int ret, rec_count = 0;
 2341 
 2342     ret = burn_drive_convert_fs_adr_sub(path, adr, &rec_count);
 2343     return ret;
 2344 }
 2345 
 2346 
 2347 /* API */
 2348 int burn_lookup_device_link(char *dev_adr, char link_adr[],
 2349             char *dir_adr, char **ranks, int rank_count, int flag)
 2350 {
 2351     DIR *dirpt= NULL;
 2352     struct dirent *entry;
 2353     struct stat link_stbuf;
 2354     char *adr= NULL, *namept, *sys_adr= NULL;
 2355     int ret, name_rank, found_rank= 0x7fffffff, dirlen, i, rec_count = 0;
 2356     static char default_ranks_data[][8] =
 2357         {"dvdrw", "cdrw", "dvd", "cdrom", "cd"};
 2358     char *default_ranks[5];
 2359 
 2360     link_adr[0] = 0;
 2361     if (ranks == NULL) {
 2362         for (i = 0; i < 5; i++)
 2363             default_ranks[i] = default_ranks_data[i]; 
 2364         ranks = default_ranks;
 2365         rank_count= 5;
 2366         }
 2367     dirlen= strlen(dir_adr) + 1;
 2368     if (strlen(dir_adr) + 1 >= BURN_DRIVE_ADR_LEN) {
 2369 
 2370         /* >>> Issue warning about oversized directory address */;
 2371 
 2372         {ret = 0; goto ex;}
 2373     }
 2374     BURN_ALLOC_MEM(adr, char, BURN_DRIVE_ADR_LEN);
 2375         BURN_ALLOC_MEM(sys_adr, char, BURN_DRIVE_ADR_LEN);
 2376 
 2377     dirpt = opendir(dir_adr);
 2378     if (dirpt == NULL)
 2379         {ret = 0; goto ex;}
 2380     strcpy(adr, dir_adr);
 2381         strcat(adr, "/");
 2382     namept = adr + strlen(dir_adr) + 1;
 2383     while(1) {
 2384         entry = readdir(dirpt);
 2385         if(entry == NULL)
 2386     break;
 2387         if (strlen(entry->d_name) + dirlen >= BURN_DRIVE_ADR_LEN)
 2388     continue;
 2389         strcpy(namept, entry->d_name);
 2390         if(lstat(adr, &link_stbuf) == -1)
 2391     continue;
 2392         if((link_stbuf.st_mode & S_IFMT) != S_IFLNK)
 2393     continue;
 2394         /* Determine rank and omit uninteresting ones */
 2395         for(name_rank= 0; name_rank < rank_count; name_rank++)
 2396             if(strncmp(namept, ranks[name_rank],
 2397                      strlen(ranks[name_rank])) == 0)
 2398         break;
 2399         /* we look for lowest rank */
 2400         if(name_rank >= rank_count ||
 2401            name_rank > found_rank ||
 2402            (name_rank == found_rank &&
 2403             strcmp(namept, link_adr + dirlen) >= 0))
 2404     continue; 
 2405 
 2406         /* Does name point to the same device as dev_adr ? */
 2407         ret= burn_drive_resolve_link(adr, sys_adr, &rec_count, 2);
 2408         if(ret < 0)
 2409             goto ex;
 2410         if(ret == 0)
 2411     continue;
 2412         if(strcmp(dev_adr, sys_adr) == 0) {
 2413             strcpy(link_adr, adr); 
 2414             found_rank= name_rank;
 2415         }
 2416     }
 2417     ret= 2;
 2418     if(found_rank < 0x7fffffff)
 2419         ret= 1;
 2420 ex:;
 2421     if(dirpt != NULL)
 2422         closedir(dirpt);
 2423     BURN_FREE_MEM(adr);
 2424     BURN_FREE_MEM(sys_adr);
 2425     return(ret);
 2426 }
 2427 
 2428 
 2429 /** A pacifier function suitable for burn_abort.
 2430     @param handle If not NULL, a pointer to a text suitable for printf("%s")
 2431 */
 2432 int burn_abort_pacifier(void *handle, int patience, int elapsed)
 2433 {
 2434  char *prefix= "libburn : ";
 2435 
 2436  if(handle!=NULL)
 2437     prefix= handle;
 2438  fprintf(stderr,
 2439          "\r%sABORT : Waiting for drive to finish ( %d s, %d max)",
 2440          (char *) prefix, elapsed, patience);
 2441  return(1);
 2442 }
 2443 
 2444 
 2445 /* ts B00226 : Outsourced backend of burn_abort()
 2446    @param flag  bit0= do not call burn_finish()
 2447 */
 2448 int burn_abort_5(int patience, 
 2449                int (*pacifier_func)(void *handle, int patience, int elapsed),
 2450                void *handle, int elapsed, int flag)
 2451 {
 2452     int ret, i, occup, still_not_done= 1, pacifier_off= 0, first_round= 1;
 2453     unsigned long wait_grain= 100000;
 2454     time_t start_time, current_time, pacifier_time, end_time;
 2455 
 2456 #ifndef NIX
 2457     time_t stdio_patience = 3;
 2458 #endif
 2459 
 2460 
 2461 /*
 2462  fprintf(stderr, 
 2463  "libburn_EXPERIMENTAL: burn_abort_5(%d,%d)\n", patience, flag);
 2464 */
 2465 
 2466     current_time = start_time = pacifier_time = time(0);
 2467     start_time -= elapsed;
 2468     end_time = start_time + patience;
 2469 
 2470     /* >>> ts A71002 : are there any threads at work ?
 2471         If not, then one can force abort because the drives will not
 2472         change status on their own.
 2473      */
 2474 
 2475     while(current_time < end_time || (patience <= 0 && first_round)) {
 2476         still_not_done = 0;
 2477 
 2478         for(i = 0; i < drivetop + 1; i++) {
 2479             occup = burn_drive_is_occupied(&(drive_array[i]));
 2480             if(occup == -2)
 2481         continue;
 2482 
 2483             if(drive_array[i].drive_role != 1) {
 2484 
 2485 #ifdef NIX
 2486 
 2487                 /* ts A90302
 2488                    <<< this causes a race condition with drive
 2489                        usage and drive disposal.
 2490                 */
 2491                 drive_array[i].busy = BURN_DRIVE_IDLE;
 2492                 burn_drive_forget(&(drive_array[i]), 1);
 2493         continue;
 2494 
 2495 #else /* NIX */
 2496 
 2497                 /* ts A90318
 2498                    >>> but if a pipe breaks then the drive
 2499                        never gets idle.
 2500                    So for now with a short patience timespan
 2501                    and eventually a deliberate memory leak.
 2502                 */
 2503                 if (current_time - start_time >
 2504                     stdio_patience) {
 2505                     drive_array[i].global_index = -1;
 2506         continue;
 2507                 }
 2508 
 2509 #endif /* ! NIX */
 2510 
 2511             }
 2512 
 2513             if(occup < 10) {
 2514                 if (!drive_array[i].cancel)
 2515                     burn_drive_cancel(&(drive_array[i]));
 2516                 if (drive_array[i].drive_role != 1)
 2517                     /* occup == -1 comes early */
 2518                     usleep(1000000);
 2519                 burn_drive_forget(&(drive_array[i]), 1);
 2520             } else if(occup <= 100) {
 2521                 if (!drive_array[i].cancel)
 2522                     burn_drive_cancel(&(drive_array[i]));
 2523                 still_not_done++;
 2524             } else if(occup <= 1000) {
 2525                 still_not_done++;
 2526             }
 2527         }
 2528         first_round = 0;
 2529 
 2530         if(still_not_done == 0 || patience <= 0)
 2531     break;
 2532         usleep(wait_grain);
 2533         current_time = time(0);
 2534         if(current_time>pacifier_time) {
 2535             if(pacifier_func != NULL && !pacifier_off) {
 2536                 ret = (*pacifier_func)(handle, patience,
 2537                         current_time-start_time);
 2538                 pacifier_off = (ret <= 0);
 2539             }
 2540             pacifier_time = current_time;
 2541         }
 2542     }
 2543     if (!(flag & 1))
 2544         burn_finish();
 2545     return(still_not_done == 0); 
 2546 }
 2547 
 2548 
 2549 /** Abort any running drive operation and finish libburn.
 2550     @param patience Maximum number of seconds to wait for drives to finish
 2551     @param pacifier_func Function to produce appeasing messages. See
 2552                          burn_abort_pacifier() for an example.
 2553     @return 1  ok, all went well
 2554             0  had to leave a drive in unclean state
 2555             <0 severe error, do no use libburn again
 2556 */
 2557 int burn_abort(int patience, 
 2558                int (*pacifier_func)(void *handle, int patience, int elapsed),
 2559                void *handle)
 2560 {
 2561     int ret, flg = 0;
 2562 
 2563     if (patience < 0) {
 2564         patience = 0;
 2565         flg |= 1;
 2566     }
 2567     ret = burn_abort_5(patience, pacifier_func, handle, 0, flg);
 2568     return ret;
 2569 }
 2570 
 2571 
 2572 /* ts A61020 API function */
 2573 int burn_drive_get_start_end_lba(struct burn_drive *d, 
 2574                 int *start_lba, int *end_lba, int flag)
 2575 {
 2576     if (d->start_lba == -2000000000 || d->end_lba == -2000000000)
 2577         return 0;
 2578     *start_lba = d->start_lba;
 2579     *end_lba= d->end_lba;
 2580     return 1;
 2581 }
 2582 
 2583 
 2584 /* ts A61020 API function */
 2585 int burn_disc_pretend_blank(struct burn_drive *d)
 2586 {
 2587     if (d->drive_role == 0)
 2588         return 0;
 2589     if (d->status != BURN_DISC_UNREADY && 
 2590         d->status != BURN_DISC_UNSUITABLE)
 2591         return 0;
 2592     d->status = BURN_DISC_BLANK;
 2593     return 1;
 2594 }
 2595 
 2596 /* ts A61106 API function */
 2597 int burn_disc_pretend_full(struct burn_drive *d)
 2598 {
 2599     if (d->drive_role == 0)
 2600         return 0;
 2601     if (d->status != BURN_DISC_UNREADY && 
 2602         d->status != BURN_DISC_UNSUITABLE)
 2603         return 0;
 2604     d->status = BURN_DISC_FULL;
 2605     return 1;
 2606 }
 2607 
 2608 /* ts B31110 API function */
 2609 int burn_disc_pretend_full_uncond(struct burn_drive *d)
 2610 {
 2611     d->status = BURN_DISC_FULL;
 2612     return 1;
 2613 }
 2614 
 2615 /* ts A61021: new API function */
 2616 int burn_disc_read_atip(struct burn_drive *d)
 2617 {
 2618     if (burn_drive_is_released(d)) {
 2619         libdax_msgs_submit(libdax_messenger,
 2620                 d->global_index, 0x0002010e,
 2621                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2622                 "Attempt to read ATIP from ungrabbed drive",
 2623                 0, 0);
 2624         return -1;
 2625     }
 2626     if(d->drive_role != 1)
 2627         return 0;
 2628     if ((d->current_profile == -1 || d->current_is_cd_profile)
 2629         && ((d->mdata->p2a_valid > 0 && d->mdata->cdrw_write) ||
 2630             d->current_profile != 0x08)) {
 2631         d->read_atip(d);
 2632         /* >>> some control of success would be nice :) */
 2633     } else {
 2634         /* mmc5r03c.pdf 6.26.3.6.3 : ATIP is undefined for non-CD
 2635            (and it seems meaningless for non-burners).
 2636            ts A90823: Pseudo-CD U3 memory stick stalls with ATIP.
 2637                       It is !cdrw_write and profile is 0x08.
 2638         */
 2639         return 0;
 2640     }
 2641     return 1;
 2642 }
 2643 
 2644 /* ts A61110 : new API function */
 2645 int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
 2646                 int trackno, int *lba, int *nwa)
 2647 {
 2648     int ret;
 2649 
 2650     if (burn_drive_is_released(d)) {
 2651         libdax_msgs_submit(libdax_messenger,
 2652             d->global_index, 0x0002011b,
 2653             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2654             "Attempt to read track info from ungrabbed drive",
 2655             0, 0);
 2656         return -1;
 2657     }
 2658     if (d->busy != BURN_DRIVE_IDLE) {
 2659         libdax_msgs_submit(libdax_messenger,
 2660             d->global_index, 0x0002011c,
 2661             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2662             "Attempt to read track info from busy drive",
 2663             0, 0);
 2664         return -1;
 2665     }
 2666     *lba = *nwa = 0;
 2667     if (d->drive_role == 5 && trackno == 0 &&
 2668         d->status == BURN_DISC_APPENDABLE) {
 2669         *lba = *nwa = d->role_5_nwa;
 2670         return 1;
 2671     }
 2672     if (d->drive_role != 1)
 2673         return 0;
 2674     if (o != NULL)
 2675         d->send_write_parameters(d, NULL, -1, o);
 2676     ret = d->get_nwa(d, trackno, lba, nwa);
 2677     return ret;
 2678 }
 2679 
 2680 
 2681 /* ts A70131 : new API function */
 2682 int burn_disc_get_msc1(struct burn_drive *d, int *start)
 2683 {
 2684     int ret, trackno;
 2685 
 2686     if (burn_drive_is_released(d)) {
 2687         libdax_msgs_submit(libdax_messenger,
 2688             d->global_index, 0x0002011b,
 2689             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2690             "Attempt to read track info from ungrabbed drive",
 2691             0, 0);
 2692         return -1;
 2693     }
 2694     if (d->busy != BURN_DRIVE_IDLE) {
 2695         libdax_msgs_submit(libdax_messenger,
 2696             d->global_index, 0x0002011c,
 2697             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2698             "Attempt to read track info from busy drive",
 2699             0, 0);
 2700         return -1;
 2701     }
 2702     *start = 0;
 2703     if (d->drive_role != 1)
 2704         return 0;
 2705     ret = d->read_multi_session_c1(d, &trackno, start);
 2706     return ret;
 2707 }
 2708 
 2709 
 2710 /* ts A70213 : new API function */
 2711 off_t burn_disc_available_space(struct burn_drive *d,
 2712                  struct burn_write_opts *o)
 2713 {
 2714     int lba, nwa, ret;
 2715     off_t bytes, start_byte = 0;
 2716 
 2717     if (burn_drive_is_released(d))
 2718         return 0;
 2719     if (d->busy != BURN_DRIVE_IDLE)
 2720         return 0;
 2721     if (d->drive_role == 0)
 2722         return 0;
 2723     if (d->drive_role != 1) {
 2724         if (o != NULL)
 2725             start_byte = o->start_byte;
 2726         ret = burn_os_stdio_capacity(d->devname, start_byte, &bytes);
 2727         if (ret != 1)
 2728             bytes = d->media_capacity_remaining;
 2729         if (bytes <= 0)
 2730             bytes = (off_t) (512 * 1024 * 1024 - 1) * (off_t) 2048;
 2731         if (bytes != d->media_capacity_remaining)
 2732             burn_drive_set_media_capacity_remaining(d, bytes);
 2733     } else {
 2734         if (o != NULL)
 2735             d->send_write_parameters(d, NULL, -1, o);
 2736         d->get_nwa(d, -1, &lba, &nwa);
 2737     }
 2738     if (o != NULL) {
 2739         if (o->start_byte > 0) {
 2740             if (o->start_byte > d->media_capacity_remaining)
 2741                 return 0;
 2742             return d->media_capacity_remaining - o->start_byte;
 2743         }
 2744     }
 2745     return d->media_capacity_remaining;
 2746 }
 2747 
 2748 
 2749 /* ts A61202 : New API function */
 2750 int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80])
 2751 {
 2752     *pno = d->current_profile;
 2753     strcpy(name,d->current_profile_text);
 2754     return *pno >= 0;
 2755 }
 2756 
 2757 
 2758 /* ts A90815 : New API function */
 2759 int burn_drive_get_all_profiles(struct burn_drive *d, int *num_profiles,
 2760                 int profiles[64], char is_current[64])
 2761 {
 2762     int i;
 2763 
 2764     *num_profiles = d->num_profiles;
 2765     for (i = 0; i < d->num_profiles; i++) {
 2766         profiles[i] = (d->all_profiles[i * 4] << 8) |
 2767                 d->all_profiles[i * 4 + 1];
 2768         is_current[i] = d->all_profiles[i * 4 + 2] & 1;
 2769     }
 2770     return 1;
 2771 }
 2772 
 2773 
 2774 /* ts A90815 : New API function */
 2775 int burn_obtain_profile_name(int profile_number, char name[80])
 2776 {
 2777     strcpy(name, mmc_obtain_profile_name(profile_number));
 2778     return(name[0] != 0);
 2779 }
 2780 
 2781 
 2782 /* ts A61223 : New API function */
 2783 int burn_drive_wrote_well(struct burn_drive *d)
 2784 {
 2785     return !d->cancel;
 2786 }
 2787 
 2788 
 2789 /* ts A61226 */
 2790 int burn_speed_descriptor_new(struct burn_speed_descriptor **s,
 2791             struct burn_speed_descriptor *prev,
 2792             struct burn_speed_descriptor *next, int flag)
 2793 {
 2794     struct burn_speed_descriptor *o;
 2795 
 2796     (*s) = o = calloc(1, sizeof(struct burn_speed_descriptor));
 2797     if (o == NULL)
 2798         return -1;
 2799     o->source = 0;
 2800     o->profile_loaded = -2;
 2801     o->profile_name[0] = 0;
 2802     o->wrc = 0;
 2803     o->exact = 0;
 2804     o->mrw = 0;
 2805     o->end_lba = -1;
 2806     o->write_speed = 0;
 2807     o->read_speed = 0;
 2808 
 2809     o->prev = prev;
 2810     if (prev != NULL) {
 2811         next = prev->next;
 2812         prev->next = o;
 2813     } 
 2814     o->next = next;
 2815     if (next != NULL)
 2816         next->prev = o;
 2817     return 1;
 2818 }
 2819 
 2820 
 2821 /* ts A61226 */
 2822 /* @param flag bit0= destroy whole next-chain of descriptors */
 2823 int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag)
 2824 {
 2825     struct burn_speed_descriptor *next, *o;
 2826 
 2827     if ((*s) == NULL)
 2828         return 0;
 2829     if (flag&1)
 2830         for (o = (*s); o->prev != NULL; o = o->prev);
 2831     else
 2832         o = (*s);
 2833     next = o->next;
 2834     if (next != NULL)
 2835         next->prev = o->prev;
 2836     if (o->prev != NULL)
 2837         o->prev->next = next;
 2838     free((char *) (*s));
 2839     (*s) = NULL;
 2840     if (flag&1)
 2841         return burn_speed_descriptor_destroy(&next, flag&1);
 2842     return 1;
 2843 }
 2844 
 2845 
 2846 /* ts A61226  */
 2847 int burn_speed_descriptor_copy(struct burn_speed_descriptor *from,
 2848             struct burn_speed_descriptor *to, int flag)
 2849 {
 2850     to->source = from->source;
 2851     to->profile_loaded = from->profile_loaded;
 2852     strcpy(to->profile_name, from->profile_name);
 2853     to->wrc = from->wrc;
 2854     to->exact = from->exact;
 2855     to->mrw = from->mrw;
 2856     to->end_lba = from->end_lba;
 2857     to->write_speed = from->write_speed;
 2858     to->read_speed = from->read_speed;
 2859     return 1;
 2860 }
 2861 
 2862 
 2863 /* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */
 2864 int burn_mdata_free_subs(struct scsi_mode_data *m)
 2865 {
 2866     burn_speed_descriptor_destroy(&(m->speed_descriptors), 1);
 2867     return 1;
 2868 }
 2869 
 2870 
 2871 /* ts A61226 : API function */
 2872 int burn_drive_get_speedlist(struct burn_drive *d,
 2873                  struct burn_speed_descriptor **speed_list)
 2874 {
 2875     int ret;
 2876     struct burn_speed_descriptor *sd, *csd = NULL;
 2877 
 2878     (*speed_list) = NULL;
 2879     for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) {
 2880         ret = burn_speed_descriptor_new(&csd, NULL, csd, 0);
 2881         if (ret <= 0)
 2882             return -1;
 2883         burn_speed_descriptor_copy(sd, csd, 0);
 2884     }
 2885     (*speed_list) = csd;
 2886     return (csd != NULL);
 2887 }
 2888 
 2889 
 2890 /* ts A70713 : API function */
 2891 int burn_drive_get_best_speed(struct burn_drive *d, int speed_goal,
 2892             struct burn_speed_descriptor **best_descr, int flag)
 2893 {
 2894     struct burn_speed_descriptor *sd;
 2895     int best_speed = 0, best_lba = 0, source= 2, speed;
 2896 
 2897     if (flag & 2)
 2898         source = -1;
 2899     if (speed_goal < 0)
 2900         best_speed = 2000000000;
 2901     *best_descr = NULL;
 2902     for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) {
 2903         if (flag & 1)
 2904             speed = sd->read_speed;
 2905         else
 2906             speed = sd->write_speed;
 2907         if ((source >= 0 && sd->source != source) || 
 2908             speed <= 0)
 2909     continue;
 2910         if (speed_goal < 0) {
 2911             if (speed < best_speed) {
 2912                 best_speed = speed;
 2913                 *best_descr = sd;
 2914             }
 2915         } else if (speed_goal == 0) {
 2916             if ((source == 2 && sd->end_lba > best_lba) ||
 2917                 ((source !=2 || sd->end_lba == best_lba) &&
 2918                  speed > best_speed)) {
 2919                 best_lba = sd->end_lba;
 2920                 best_speed = speed;
 2921                 *best_descr = sd;
 2922             }
 2923         } else if (speed <= speed_goal) {
 2924             if (speed > best_speed) {
 2925                 best_speed = speed;
 2926                 *best_descr = sd;
 2927             }
 2928         }
 2929     }
 2930     if (d->current_is_cd_profile && *best_descr == NULL && ! (flag & 2))
 2931         /* Mode page 2Ah is deprecated in MMC-5 although all known
 2932            burners still support it with CD media. */
 2933         return burn_drive_get_best_speed(d, speed_goal, best_descr,
 2934                          flag | 2);
 2935     return (*best_descr != NULL);
 2936 }
 2937 
 2938 
 2939 /* ts A61226 : API function */
 2940 int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list)
 2941 {
 2942     return burn_speed_descriptor_destroy(speed_list, 1);
 2943 }
 2944 
 2945 
 2946 /* ts A70203 : API function */
 2947 int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
 2948                          struct burn_multi_caps **caps, int flag)
 2949 {
 2950     enum burn_disc_status s;
 2951     struct burn_multi_caps *o;
 2952     int status, num_formats, ret, type, i;
 2953     off_t size;
 2954     unsigned dummy;
 2955 
 2956     *caps = NULL;
 2957     s = burn_disc_get_status(d);
 2958     if(s == BURN_DISC_UNGRABBED)
 2959         return -1;
 2960     *caps = o = (struct burn_multi_caps *)
 2961         calloc(1, sizeof(struct burn_multi_caps));
 2962     if(*caps == NULL)
 2963         return -1;
 2964     /* Default says nothing is available */
 2965     o->multi_session = o->multi_track = 0;
 2966     o-> start_adr = 0;
 2967     o->start_alignment = o->start_range_low = o->start_range_high = 0;
 2968     o->might_do_tao = o->might_do_sao = o->might_do_raw = 0;
 2969     o->advised_write_mode = BURN_WRITE_NONE;
 2970     o->selected_write_mode = wt;
 2971     o->current_profile = d->current_profile;
 2972     o->current_is_cd_profile = d->current_is_cd_profile;
 2973         o->might_simulate = 0;
 2974     
 2975     if (d->drive_role == 0 || d->drive_role == 4)
 2976         return 0;
 2977     if (d->drive_role == 2) {
 2978         /* stdio file drive : random access read-write */
 2979         o->start_adr = 1;
 2980         size = d->media_capacity_remaining;
 2981         burn_os_stdio_capacity(d->devname, 0, &size);
 2982         burn_drive_set_media_capacity_remaining(d, size);
 2983         o->start_range_high = d->media_capacity_remaining - 2048;
 2984         o->start_alignment = 2048; /* imposting a drive, not a file */
 2985         o->might_do_sao = 4;
 2986         o->might_do_tao = 2;
 2987         o->advised_write_mode = BURN_WRITE_TAO;
 2988             o->might_simulate = 1;
 2989     } else if (d->drive_role == 5) {
 2990         /* stdio file drive : random access write-only */
 2991         o->start_adr = 1;
 2992         size = d->media_capacity_remaining;
 2993         burn_os_stdio_capacity(d->devname, 0, &size);
 2994         burn_drive_set_media_capacity_remaining(d, size);
 2995 
 2996         /* >>> start_range_low = file size rounded to 2048 */;
 2997 
 2998         o->start_range_high = d->media_capacity_remaining - 2048;
 2999         o->start_alignment = 2048; /* imposting a drive, not a file */
 3000         if (s == BURN_DISC_APPENDABLE) {
 3001             if (wt == BURN_WRITE_SAO || wt == BURN_WRITE_RAW)
 3002                 return 0;
 3003             o->might_do_sao = 0;
 3004         } else
 3005             o->might_do_sao = 4;
 3006         o->might_do_tao = 2;
 3007         o->advised_write_mode = BURN_WRITE_TAO;
 3008             o->might_simulate = 1;
 3009     } else if (d->drive_role != 1) {
 3010         /* stdio file drive : sequential access write-only */
 3011         o->might_do_sao = 4;
 3012         o->might_do_tao = 2;
 3013         o->advised_write_mode = BURN_WRITE_TAO;
 3014             o->might_simulate = 1;
 3015     } else if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) {
 3016         return 0;
 3017     } else if (s == BURN_DISC_APPENDABLE &&
 3018          (wt == BURN_WRITE_SAO || wt == BURN_WRITE_RAW)) {
 3019         return 0;
 3020     } else if (wt == BURN_WRITE_RAW && !d->current_is_cd_profile) {
 3021         return 0;
 3022     } else if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
 3023          /* CD-R , CD-RW */
 3024         if (d->block_types[BURN_WRITE_TAO]) {
 3025             o->multi_session = o->multi_track = 1;
 3026             o->might_do_tao = 2;
 3027             if (o->advised_write_mode == BURN_WRITE_NONE)
 3028                 o->advised_write_mode = BURN_WRITE_TAO;
 3029         }
 3030         if (d->block_types[BURN_WRITE_SAO]) {
 3031             o->multi_session = o->multi_track = 1;
 3032             o->might_do_sao = 1;
 3033             if (o->advised_write_mode == BURN_WRITE_NONE)
 3034                 o->advised_write_mode = BURN_WRITE_SAO;
 3035         }
 3036         if (d->block_types[BURN_WRITE_RAW]) {
 3037             o->might_do_raw = 1;
 3038             if (o->advised_write_mode == BURN_WRITE_NONE)
 3039                 o->advised_write_mode = BURN_WRITE_RAW;
 3040         }
 3041         if (wt == BURN_WRITE_RAW)
 3042             o->multi_session = o->multi_track = 0;
 3043         else if(wt == BURN_WRITE_NONE || wt == BURN_WRITE_SAO ||
 3044             wt == BURN_WRITE_TAO)
 3045             o->might_simulate = !!(d->mdata->p2a_valid > 0 &&
 3046                                    d->mdata->simulate);
 3047     } else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
 3048             d->current_profile == 0x15) {
 3049         /* DVD-R , sequential DVD-RW , DVD-R/DL Sequential */
 3050         if (s == BURN_DISC_BLANK) {
 3051             o->might_do_sao = 1;
 3052             o->advised_write_mode = BURN_WRITE_SAO;
 3053         }
 3054         if (d->current_has_feat21h) {
 3055 #ifndef Libburn_dvd_r_dl_multi_no_close_sessioN
 3056             if (d->current_profile != 0x15)
 3057 #endif
 3058                 o->multi_session = 1;
 3059             o->multi_track = 1;
 3060             o->might_do_tao = 2;
 3061             o->advised_write_mode = BURN_WRITE_TAO;
 3062         }
 3063         if (wt == BURN_WRITE_SAO)
 3064             o->multi_session = o->multi_track = 0;
 3065         if (wt == BURN_WRITE_NONE || wt == BURN_WRITE_SAO ||
 3066             wt == BURN_WRITE_TAO)
 3067             o->might_simulate = 1;
 3068     } else if (d->current_profile == 0x12 ||
 3069             d->current_profile == 0x13 ||
 3070             d->current_profile == 0x1a ||
 3071             d->current_profile == 0x43 
 3072               ) {
 3073         /* DVD-RAM, overwritable DVD-RW, DVD+RW, BD-RE */
 3074         o->start_adr = 1;
 3075         ret = burn_disc_get_formats(d, &status, &size, &dummy,
 3076                     &num_formats);
 3077         if (ret == 1) {
 3078             if (status == BURN_FORMAT_IS_FORMATTED)
 3079                 o->start_range_high = size - 2048;
 3080             if (d->current_profile == 0x13) {
 3081                 o->start_alignment = 32 * 1024;
 3082                 for (i = 0; i < num_formats; i++) {
 3083                     ret = burn_disc_get_format_descr(d, i,
 3084                         &type, &size, &dummy);
 3085                     if (ret <= 0)
 3086                 continue;
 3087                     if (type == 0x13) /* expandable */
 3088                 break;
 3089                 }
 3090                 if (i >= num_formats) /* not expandable */
 3091                     o->start_range_high -= 32 * 1024;
 3092                 if (o->start_range_high < 0)
 3093                     o->start_range_high = 0;
 3094             } else {
 3095                 o->start_alignment = 2 * 1024;
 3096                 if (d->best_format_size - 2048 >
 3097                              o->start_range_high)
 3098                     o->start_range_high =
 3099                         d->best_format_size - 2048;
 3100             }
 3101         }
 3102         o->might_do_sao = 4;
 3103         o->might_do_tao = 2;
 3104         o->advised_write_mode = BURN_WRITE_TAO;
 3105     } else if (d->current_profile == 0x1b || d->current_profile == 0x2b ||
 3106            d->current_profile == 0x41) {
 3107         /* DVD+R , DVD+R/DL , BD-R SRM */
 3108         o->multi_session = o->multi_track = 1;
 3109         o->might_do_tao = 2;
 3110         o->might_do_sao = 1;
 3111         o->advised_write_mode = BURN_WRITE_TAO;
 3112     } else /* unknown media */
 3113         return 0;
 3114         
 3115     if (s == BURN_DISC_APPENDABLE)
 3116         o->might_do_sao = o->might_do_raw = 0;
 3117 
 3118     if (wt == BURN_WRITE_TAO && !o->might_do_tao)
 3119         return 0;
 3120     else if (wt == BURN_WRITE_SAO && !o->might_do_sao)
 3121         return 0;
 3122     else if (wt == BURN_WRITE_RAW && !o->might_do_raw)
 3123         return 0;
 3124     return 1;
 3125 }
 3126 
 3127 
 3128 /* ts A70203 : API function */
 3129 int burn_disc_free_multi_caps(struct burn_multi_caps **caps)
 3130 {
 3131     if (*caps == NULL)
 3132         return 0;
 3133     free((char *) *caps);
 3134     *caps = NULL;
 3135     return 1;
 3136 }
 3137 
 3138 
 3139 /* ts A70207 : evaluate write mode related peculiarities of a disc
 3140    @param flag bit0= fill_up_media is active
 3141 */
 3142 int burn_disc_get_write_mode_demands(struct burn_disc *disc,
 3143             struct burn_write_opts *opts,
 3144             struct burn_disc_mode_demands *result, int flag)
 3145 {
 3146     struct burn_session *session;
 3147     struct burn_track *track;
 3148     int i, j, mode, unknown_track_sizes = 0, last_track_is_unknown = 0;
 3149     enum burn_disc_status s;
 3150     
 3151 
 3152     memset((char *) result, 0, sizeof(struct burn_disc_mode_demands));
 3153     if (disc == NULL)
 3154         return 2;
 3155     s = burn_disc_get_status(opts->drive);
 3156     if (s == BURN_DISC_APPENDABLE || disc->sessions > 1)
 3157         result->will_append = 1;
 3158     if (disc->sessions > 1)
 3159         result->multi_session = 1;
 3160     for (i = 0; i < disc->sessions; i++) {
 3161         session = disc->session[i];
 3162         if (session->tracks <= 0)
 3163     continue;
 3164         mode = session->track[0]->mode;
 3165         if (session->tracks > 1)
 3166             result->multi_track = 1;
 3167         for (j = 0; j < session->tracks; j++) {
 3168             track = session->track[j];
 3169             if (burn_track_is_open_ended(track)) {
 3170                 if (burn_track_get_default_size(track) > 0) {
 3171                     if (result->unknown_track_size == 0)
 3172                         result->unknown_track_size = 2;
 3173                 } else
 3174                     result->unknown_track_size = 1;
 3175                 unknown_track_sizes++;
 3176                 last_track_is_unknown = 1;
 3177             } else
 3178                 last_track_is_unknown = 0;
 3179             if ((mode & BURN_MODE_BITS) !=
 3180                         (track->mode & BURN_MODE_BITS))
 3181                 result->mixed_mode = 1;
 3182             if (track->mode & BURN_MODE1) {
 3183                 result->block_types |= BURN_BLOCK_MODE1;
 3184             } else if (track->mode & BURN_AUDIO) {
 3185                 result->audio = 1;
 3186                 result->block_types |= BURN_BLOCK_RAW0;
 3187                 result->exotic_track = 1;
 3188             } else {
 3189                 result->block_types |= opts->block_type;
 3190                 result->exotic_track = 1;
 3191             }
 3192         }
 3193     }
 3194     if (flag&1) {/* fill_up_media will define the size of the last track */
 3195         if (unknown_track_sizes == 1 && last_track_is_unknown)
 3196             result->unknown_track_size = 0;
 3197     }
 3198     return (disc->sessions > 0);
 3199 }
 3200 
 3201 
 3202 /* ts A70903 : API */
 3203 int burn_drive_get_drive_role(struct burn_drive *d)
 3204 {
 3205     return d->drive_role;
 3206 }
 3207 
 3208 
 3209 /* ts A70923
 3210    Hands out pointers *dpt to directory path and *npt to basename.
 3211    Caution: the last '/' in adr gets replaced by a 0.
 3212 */
 3213 static int burn__split_path(char *adr, char **dpt, char **npt)
 3214 {
 3215     *dpt = adr;
 3216     *npt = strrchr(*dpt, '/');
 3217     if (*npt == NULL) {
 3218         *npt = *dpt;
 3219         *dpt = ".";
 3220         return 1;
 3221     }
 3222     **npt = 0;
 3223     if(*npt == *dpt) 
 3224         *dpt = "/";
 3225     (*npt)++;
 3226     return 2;
 3227 }
 3228 
 3229 
 3230 /* ts A70923 : API */
 3231 int burn_drive_equals_adr(struct burn_drive *d1, char *adr2_in, int role2)
 3232 {
 3233     struct stat stbuf1, stbuf2;
 3234     char *adr1 = NULL, *adr2 = adr2_in;
 3235     char *conv_adr1 = NULL, *conv_adr2 = NULL;
 3236     char *npt1, *dpt1, *npt2, *dpt2;
 3237     int role1, stat_ret1, stat_ret2, conv_ret2, exact_role_matters = 0, fd;
 3238     int ret;
 3239 
 3240     BURN_ALLOC_MEM(adr1, char, BURN_DRIVE_ADR_LEN);
 3241     BURN_ALLOC_MEM(conv_adr1, char, BURN_DRIVE_ADR_LEN);
 3242     BURN_ALLOC_MEM(conv_adr2, char, BURN_DRIVE_ADR_LEN);
 3243 
 3244     role1 = burn_drive_get_drive_role(d1);
 3245     burn_drive_d_get_adr(d1, adr1);
 3246     stat_ret1 = stat(adr1, &stbuf1);
 3247 
 3248     /* If one of the candidate paths depicts an open file descriptor then
 3249        its read-write capability decides about its role and the difference
 3250        between roles 2 and 3 does matter.
 3251     */
 3252     fd = burn_drive__fd_from_special_adr(d1->devname);
 3253     if (fd != -1)
 3254         exact_role_matters = 1;
 3255     if (strncmp(adr2, "stdio:", 6) == 0) {
 3256         adr2+= 6;
 3257         if (adr2[0] == 0) {
 3258             role2 = 0;
 3259         } else {
 3260             fd = burn_drive__fd_from_special_adr(adr2);
 3261             if (fd != -1)
 3262                 exact_role_matters = 1;
 3263             ret = burn_drive__is_rdwr(adr2, NULL, NULL, NULL,
 3264                                     1 | 2);
 3265             if (ret == 2 && (burn_drive_role_4_allowed & 1))
 3266                 role2 = 4;
 3267             else if (ret == 3 && (burn_drive_role_4_allowed & 1))
 3268                 role2 = 5;
 3269             else if (ret > 0)
 3270                 role2 = 2;
 3271             else
 3272                 role2 = 3;
 3273             if (fd == -1 &&
 3274                 role2 == 2 && (burn_drive_role_4_allowed & 3) == 3)
 3275                 role2 = burn_role_by_access(adr2,
 3276                         !!(burn_drive_role_4_allowed & 4));
 3277         }
 3278     }
 3279 
 3280     if (strlen(adr2) >= BURN_DRIVE_ADR_LEN)
 3281         {ret = -1; goto ex;}
 3282     stat_ret2 = stat(adr2, &stbuf2);
 3283     conv_ret2 = burn_drive_convert_fs_adr(adr2, conv_adr2);
 3284 
 3285     if (!exact_role_matters) {
 3286         /* roles >= 2 have the same name space and object
 3287            interpretation */
 3288         if (role1 >= 2)
 3289             role1 = 2;
 3290         if (role2 >= 2)
 3291             role2 = 2;
 3292     }
 3293 
 3294     if (strcmp(adr1, adr2) == 0 && role1 == role2)
 3295         {ret = 1; goto ex;}     /* equal role and address */
 3296     if (role1 == 1 && role2 == 1) {
 3297                     /* MMC drive meets wannabe MMC drive */
 3298         if (conv_ret2 <= 0)
 3299             {ret = 0; goto ex;} /* no MMC drive at adr2 */
 3300         if (strcmp(adr1, conv_adr2) == 0)
 3301             {ret = 1; goto ex;} /* equal real MMC drives */
 3302         {ret = 0; goto ex;}
 3303 
 3304     } else if (role1 == 0 || role2 == 0)
 3305         {ret = 0; goto ex;}     /* one null-drive, one not */
 3306 
 3307     else if (role1 != 1 && role2 != 1) {
 3308                     /* pseudo-drive meets file object */
 3309 
 3310         if (role1 != role2)
 3311             {ret = 0; goto ex;}
 3312         if (stat_ret1 == -1 || stat_ret2 == -1) {
 3313             if (stat_ret1 != -1 || stat_ret2 != -1)
 3314                  {ret = 0; goto ex;}
 3315                     /* one address existing, one not */
 3316 
 3317             /* Two non-existing file objects */
 3318 
 3319             strcpy(conv_adr1, adr1);
 3320             burn__split_path(conv_adr1, &dpt1, &npt1);
 3321             strcpy(conv_adr2, adr2);
 3322             burn__split_path(conv_adr2, &dpt2, &npt2);
 3323             if (strcmp(npt1, npt2))
 3324                 {ret = 0; goto ex;} /* basenames differ */
 3325             stat_ret1= stat(adr1, &stbuf1);
 3326             stat_ret2= stat(adr2, &stbuf2);
 3327             if (stat_ret1 != stat_ret2)
 3328                  {ret = 0; goto ex;}
 3329                         /* one dir existing, one not */
 3330 
 3331             /* Both directories exist. The basenames are equal.
 3332                So the addresses are equal if the directories are
 3333                equal.*/
 3334         }
 3335         if (stbuf1.st_ino == stbuf2.st_ino &&
 3336             stbuf1.st_dev == stbuf2.st_dev)
 3337             {ret = 1; goto ex;} /* same filesystem object */
 3338 
 3339         if (S_ISBLK(stbuf1.st_mode) && S_ISBLK(stbuf2.st_mode) &&
 3340              stbuf1.st_rdev == stbuf2.st_rdev)
 3341             {ret = 1; goto ex;}/* same major,minor device number */
 3342         if (S_ISCHR(stbuf1.st_mode) && S_ISCHR(stbuf2.st_mode) &&
 3343              stbuf1.st_rdev == stbuf2.st_rdev)
 3344             {ret = 1; goto ex;}/* same major,minor device number */
 3345 
 3346         /* Are both filesystem objects related to the same MMC drive */
 3347         if (conv_ret2 <= 0)
 3348             {ret = 0; goto ex;} /* no MMC drive at adr2 */
 3349         if (burn_drive_convert_fs_adr(adr1, conv_adr1) <= 0)
 3350             {ret = 0; goto ex;} /* no MMC drive at adr1 */
 3351         if (strcmp(conv_adr1, conv_adr2) == 0)
 3352             {ret = 1; goto ex;} /* same MMC drive */
 3353 
 3354         {ret = 0; goto ex;}  /* all filesystem disguises are checked */
 3355 
 3356     } else if (role1 == 1 && role2 != 1) {
 3357                               /* MMC drive meets file object */
 3358 
 3359         if (conv_ret2 <= 0)
 3360             {ret = 0; goto ex;} /* no MMC drive at adr2 */
 3361         if (strcmp(adr1, conv_adr2) == 0)
 3362             {ret = 1; goto ex;} /* same MMC drive */
 3363         {ret = 0; goto ex;}
 3364 
 3365     } else if (role1 != 1 && role2 == 1) {
 3366                               /* stdio-drive meets wannabe MMC drive */
 3367 
 3368         if (conv_ret2 <= 0)
 3369             {ret = 0; goto ex;}  /* no MMC drive at adr2 */
 3370         if (burn_drive_convert_fs_adr(adr1, conv_adr1) <= 0)
 3371             {ret = 0; goto ex;}  /* no MMC drive at adr1 */
 3372         if (strcmp(conv_adr1, conv_adr2) == 0)
 3373             {ret = 1; goto ex;}  /* same MMC drive */
 3374         {ret = 0; goto ex;}
 3375 
 3376     }
 3377     ret = 0;
 3378 ex:;
 3379     BURN_FREE_MEM(adr1);
 3380     BURN_FREE_MEM(conv_adr1);
 3381     BURN_FREE_MEM(conv_adr2);
 3382     return ret;
 3383 }
 3384 
 3385 
 3386 int burn_drive_find_by_thread_pid(struct burn_drive **d, pid_t pid,
 3387                                  pthread_t tid)
 3388 {
 3389     int i;
 3390 
 3391     for (i = 0; i < drivetop + 1; i++) {
 3392 
 3393 /*
 3394         if (drive_array[i].thread_pid_valid)
 3395             fprintf(stderr, "libburn_EXPERIMENTAL : drive %d , thread_pid %d\n", i, drive_array[i].thread_pid);
 3396 */
 3397 
 3398         if (drive_array[i].thread_pid_valid &&
 3399             drive_array[i].thread_pid == pid &&
 3400             pthread_equal(drive_array[i].thread_tid, tid)) {
 3401             *d = &(drive_array[i]);
 3402             return 1;
 3403         }
 3404     }
 3405     return 0;
 3406 }
 3407 
 3408 
 3409 /* ts A80422 : centralizing this setting for debugging purposes
 3410 */
 3411 int burn_drive_set_media_capacity_remaining(struct burn_drive *d, off_t value)
 3412 {
 3413     if (value / (off_t) 2048 > (off_t) 0x7ffffff0)
 3414         value = ((off_t) 0x7ffffff0) * (off_t) 2048;
 3415     d->media_capacity_remaining = value;
 3416     return 1;
 3417 }
 3418 
 3419 
 3420 /* ts A81215 : API */
 3421 int burn_get_read_capacity(struct burn_drive *d, int *capacity, int flag)
 3422 {
 3423     *capacity = d->media_read_capacity +
 3424             (d->media_read_capacity != 0x7fffffff);
 3425     return (d->media_read_capacity != 0x7fffffff);
 3426 }
 3427 
 3428 
 3429 /* ts A90903 : API */
 3430 int burn_disc_get_media_id(struct burn_drive *d,
 3431     char **product_id, char **media_code1, char **media_code2,
 3432     char **book_type, int flag)
 3433 {
 3434     int ret;
 3435 
 3436     *product_id = *media_code1 = *media_code2 = *book_type = NULL;
 3437     if (burn_drive_get_drive_role(d) != 1)
 3438         return 0;
 3439     ret = mmc_get_media_product_id(d,
 3440              product_id, media_code1, media_code2, book_type,
 3441              flag & 1);
 3442     return ret;
 3443 }
 3444 
 3445 
 3446 /* ts A90909 : API */
 3447 /**
 3448     @param valid   Replies bits which indicate the validity of other reply
 3449                    parameters or the state of certain CD info bits:
 3450                    bit0= disc_type valid
 3451                    bit1= disc_id valid
 3452                    bit2= bar_code valid
 3453                    bit3= disc_app_code valid
 3454                    bit4= Disc is unrestricted (URU bit)
 3455                    bit5= Disc is nominally erasable (Erasable bit)
 3456                          This will be set with overwritable media which
 3457                          libburn normally considers to be unerasable blank.
 3458 */
 3459 int burn_disc_get_cd_info(struct burn_drive *d, char disc_type[80],
 3460             unsigned int *disc_id, char bar_code[9], int *app_code,
 3461             int *valid)
 3462 {
 3463     if (d->disc_type == 0x00) {
 3464         strcpy(disc_type, "CD-DA or CD-ROM");
 3465     } else if (d->disc_type == 0x10) {
 3466         strcpy(disc_type, "CD-I");
 3467     } else if (d->disc_type == 0x20) {
 3468         strcpy(disc_type, "CD-ROM XA");
 3469     } else {
 3470         strcpy(disc_type, "undefined");
 3471     }
 3472     *disc_id = d->disc_id;
 3473     memcpy(bar_code, d->disc_bar_code, 8);
 3474     bar_code[8]= 0;
 3475     *app_code = d->disc_app_code;
 3476     *valid =  d->disc_info_valid;
 3477     return 1;
 3478 }
 3479 
 3480 
 3481 /* ts B00924 : API */
 3482 int burn_disc_get_bd_spare_info(struct burn_drive *d,
 3483                 int *alloc_blocks, int *free_blocks, int flag)
 3484 {
 3485     int ret;
 3486 
 3487     if (burn_drive_get_drive_role(d) != 1)
 3488         return 0;
 3489     *alloc_blocks = *free_blocks = 0;
 3490     ret = mmc_get_bd_spare_info(d, alloc_blocks, free_blocks, 0);
 3491     return ret;
 3492 }
 3493 
 3494 
 3495 /* ts B10801 : API */
 3496 int burn_disc_get_phys_format_info(struct burn_drive *d, int *disk_category,
 3497                         char **book_name, int *part_version, int *num_layers,
 3498                         int *num_blocks, int flag)
 3499 {
 3500     int ret;
 3501 
 3502     if (burn_drive_get_drive_role(d) != 1)
 3503         return 0;
 3504     *disk_category = *part_version = *num_layers = *num_blocks = 0;
 3505     ret = mmc_get_phys_format_info(d, disk_category, book_name,
 3506                 part_version, num_layers, num_blocks, 0);
 3507     return ret;
 3508 }
 3509 
 3510 
 3511 
 3512 /* ts B10525 : API */
 3513 int burn_disc_next_track_is_damaged(struct burn_drive *d, int flag)
 3514 {
 3515     return d->next_track_damaged;
 3516 }
 3517 
 3518 
 3519 /* ts B11201 : API */
 3520 /* Read the CD-TEXT data from the Lead-in of an Audio CD
 3521 */
 3522 int burn_disc_get_leadin_text(struct burn_drive *d,
 3523                               unsigned char **text_packs, int *num_packs,
 3524                               int flag)
 3525 {
 3526     int ret;
 3527 
 3528     ret = mmc_get_leadin_text(d, text_packs, num_packs, 0);
 3529     return ret;
 3530 }
 3531 
 3532 
 3533 /* ts B31023 API */
 3534 /* Inquire for DVD-RW failure of TAO
 3535 */
 3536 int burn_drive_was_feat21_failure(struct burn_drive *d)
 3537 {
 3538     return !!d->was_feat21h_failure;
 3539 }
 3540 
 3541 
 3542 /* ts B40106 */
 3543 int burn_feature_descr_new(struct burn_feature_descr **new,
 3544                            unsigned char *descr, int descr_len, int flag)
 3545 {
 3546     struct burn_feature_descr *o;
 3547 
 3548     *new = NULL;
 3549     if (descr_len < 4)
 3550         return 0;
 3551     (*new) = o = calloc(1, sizeof(struct burn_feature_descr));
 3552     if (o == NULL)
 3553         return -1;
 3554     o->feature_code = (descr[0] << 8) | descr[1];
 3555         o->flags = descr[2];
 3556         if (descr[3] > descr_len - 4)
 3557         o->data_lenght = 0;
 3558     else
 3559             o->data_lenght = descr[3];
 3560         o->data = NULL;
 3561         o->next = NULL;
 3562         if (o->data_lenght > 0) {
 3563         o->data = calloc(1, o->data_lenght);
 3564         if (o->data == NULL) {
 3565             burn_feature_descr_free(new, 0);
 3566             return -1;
 3567         }
 3568         memcpy(o->data, descr + 4, o->data_lenght);
 3569     }
 3570     return 1;
 3571 }
 3572 
 3573 
 3574 /* ts B40106 */
 3575 int burn_feature_descr_free(struct burn_feature_descr **descr, int flag)
 3576 {
 3577     struct burn_feature_descr *o, *next;
 3578 
 3579     if (*descr == NULL)
 3580         return 0;
 3581     for (o = *descr; o != NULL; o = next) {
 3582         next = o->next;
 3583         if (o->data != NULL)
 3584             free(o->data);
 3585         free((char *) o);
 3586     }
 3587     *descr = NULL;
 3588     return 1;
 3589 }
 3590 
 3591 
 3592 /* ts B40107 */
 3593 int burn_drive_has_feature(struct burn_drive *d, int feature_code,
 3594                            struct burn_feature_descr **descr, int flag)
 3595 {
 3596     struct burn_feature_descr *o;
 3597 
 3598     for (o = d->features; o != NULL; o = o->next) {
 3599         if (o->feature_code == feature_code) {
 3600             if (descr != NULL)
 3601                 *descr = o;
 3602             return 1;
 3603         }
 3604     }
 3605     return 0;
 3606 }
 3607 
 3608 
 3609 /* ts B51016 API */
 3610 int burn_drive_get_serial_no(struct burn_drive *d, char **sno, int *sno_len)
 3611 {
 3612     int ret;
 3613 
 3614     if (*sno != NULL)
 3615         BURN_FREE_MEM(*sno);
 3616     if (d->drive_serial_number_len > 0)
 3617         *sno_len = d->drive_serial_number_len;
 3618     else
 3619         *sno_len = 0;
 3620     BURN_ALLOC_MEM(*sno, char, *sno_len + 1);
 3621     if (d->drive_serial_number_len > 0)
 3622         memcpy(*sno, d->drive_serial_number, *sno_len);
 3623     (*sno)[*sno_len] = 0;
 3624     ret = 1;
 3625 ex:
 3626     return ret;
 3627 }
 3628 
 3629 
 3630 /* ts B51016 API */
 3631 int burn_drive_get_media_sno(struct burn_drive *d, char **sno, int *sno_len)
 3632 {
 3633     int ret;
 3634 
 3635 #ifdef Libburn_enable_scsi_cmd_ABh
 3636     struct burn_feature_descr *feat;
 3637 #endif
 3638 
 3639     if (*sno != NULL)
 3640         BURN_FREE_MEM(*sno);
 3641     *sno = NULL;
 3642 
 3643     if (d->media_serial_number_len == -1) {
 3644 
 3645 #ifdef Libburn_enable_scsi_cmd_ABh
 3646 
 3647         if (burn_drive_has_feature(d, 0x109, &feat, 0))
 3648 
 3649 #ifndef Libburn_enable_scsi_cmd_ABh_pretend_currenT
 3650             if (feat->flags & 1) /* current */
 3651 #endif
 3652 
 3653                 spc_read_media_serial_number(d);
 3654 
 3655 #else
 3656         ;
 3657 
 3658 #endif /* ! Libburn_enable_scsi_cmd_ABh */
 3659 
 3660     }
 3661 
 3662     if (d->media_serial_number_len > 0)
 3663         *sno_len = d->media_serial_number_len;
 3664     else
 3665         *sno_len = 0;
 3666     BURN_ALLOC_MEM(*sno, char, *sno_len + 1);
 3667     if (*sno_len > 0)
 3668         memcpy(*sno, d->media_serial_number, *sno_len);
 3669     (*sno)[*sno_len] = 0;
 3670     ret = 1;
 3671 ex:
 3672     return ret;
 3673 }
 3674 
 3675 
 3676 int burn_drive_get_bd_r_pow(struct burn_drive *d)
 3677 {
 3678     struct burn_feature_descr *feature;
 3679 
 3680     if (d->current_profile == 0x41)
 3681         if (burn_drive_has_feature(d, 0x38, &feature, 0) == 1)
 3682             if (feature->flags & 1)
 3683                 return 1;
 3684     return 0;
 3685 }
 3686 
 3687 
 3688 int burn_drive_set_immed(struct burn_drive *drive, int enable)
 3689 {
 3690     drive->do_no_immed = !enable;
 3691     return 1;
 3692 }
 3693 
 3694 
 3695 int burn_drive_get_immed(struct burn_drive *drive)
 3696 {
 3697     return !drive->do_no_immed;
 3698 }
 3699 
 3700 
 3701 /* ts B90412 , API */
 3702 int burn_drive_get_feature(struct burn_drive *d, unsigned int feature_code,
 3703                unsigned char *flags,
 3704                unsigned char *additional_length,
 3705                unsigned char **feature_data,
 3706                char **feature_text)
 3707 {
 3708     int ret, i;
 3709     struct burn_feature_descr *descr;
 3710 
 3711     *flags = 0;
 3712     *additional_length = 0;
 3713     *feature_data = NULL;
 3714     if (feature_text != NULL)
 3715         *feature_text = NULL;
 3716     if (!burn_drive_has_feature(d, feature_code, &descr, 0))
 3717         return 0;
 3718     *flags = descr->flags;
 3719     *additional_length = descr->data_lenght;
 3720     if (*additional_length > 0)
 3721         BURN_ALLOC_MEM(*feature_data, unsigned char,
 3722                    *additional_length);
 3723     for (i = 0; i < *additional_length; i++)
 3724         (*feature_data)[i] = descr->data[i];
 3725     
 3726     if (feature_text != NULL) {
 3727         ret = burn_make_feature_text(d, feature_code, *flags,
 3728                     *additional_length, *feature_data,
 3729                     feature_text, 0);
 3730     } else {
 3731         ret = 1;
 3732     }
 3733 ex:
 3734     return ret;
 3735 }
 3736 
 3737 
 3738 /* ts B90412 , API */
 3739 void burn_drive_get_feature_codes(struct burn_drive *d,
 3740                   int *count, unsigned int **feature_codes)
 3741 {
 3742     struct burn_feature_descr *o;
 3743     int to_alloc;
 3744 
 3745     *count = 0;
 3746     *feature_codes = NULL;
 3747     for (o = d->features; o != NULL; o = o->next)
 3748         (*count)++;
 3749     if (*count == 0)
 3750         return;
 3751     to_alloc = *count;
 3752     *count = 0;
 3753     BURN_ALLOC_MEM_VOID(*feature_codes, unsigned int, to_alloc);
 3754     for (o = d->features; o != NULL; o = o->next) {
 3755         (*feature_codes)[*count] = o->feature_code;
 3756         (*count)++;
 3757     }
 3758 ex:;
 3759 }
 3760