"Fossies" - the Fresh Open Source Software Archive

Member "libisoburn-1.5.4/xorriso/drive_mgt.c" (8 Dec 2020, 119009 Bytes) of package /linux/misc/libisoburn-1.5.4.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_mgt.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.5.2.

    1 
    2 /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
    3 
    4    Copyright 2007-2020 Thomas Schmitt, <scdbackup@gmx.net>
    5 
    6    Provided under GPL version 2 or later.
    7 
    8    This file contains functions which operate on drives and media.
    9 */
   10 
   11 #ifdef HAVE_CONFIG_H
   12 #include "../config.h"
   13 #endif
   14 
   15 #include <ctype.h>
   16 #include <sys/types.h>
   17 #include <unistd.h>
   18 #include <stdlib.h>
   19 #include <stdio.h>
   20 #include <string.h>
   21 #include <sys/stat.h>
   22 #include <sys/time.h>
   23 #include <time.h>
   24 #include <errno.h>
   25 #include <pthread.h>
   26 
   27 
   28 #include "xorriso.h"
   29 #include "xorriso_private.h"
   30 
   31 #include "lib_mgt.h"
   32 #include "drive_mgt.h"
   33 #include "iso_img.h"
   34 #include "sort_cmp.h"
   35 #include "write_run.h"
   36 #include "read_run.h"
   37 
   38 
   39 static const char *un0(const char *text)
   40 {
   41  if(text == NULL)
   42    return("");
   43  return(text);
   44 }
   45 
   46 
   47 
   48 
   49 int Xorriso_auto_driveadr(struct XorrisO *xorriso, char *adr, char *result,
   50                           int flag)
   51 {
   52  int ret, is_known_mmc= 0, does_exist= 0;
   53  char *path_pt, *libburn_adr= NULL;
   54  char *abs_pt, *abs_adr= NULL;
   55  struct stat stbuf;
   56 
   57  Xorriso_alloc_meM(libburn_adr, char, BURN_DRIVE_ADR_LEN + SfileadrL);
   58  Xorriso_alloc_meM(abs_adr, char, SfileadrL);
   59  path_pt= adr;
   60  if(strncmp(adr, "stdio:", 6) == 0)
   61    path_pt= adr + 6;
   62  else if(strncmp(adr, "mmc:", 4) == 0)
   63    path_pt= adr + 4;
   64 
   65 
   66  /* <<< replace by Xorriso_normalize_img_path() ? */;
   67 
   68  if(path_pt[0] != '/') {
   69    abs_pt= getcwd(abs_adr, SfileadrL - 1);
   70    if(abs_pt == NULL) {
   71      Xorriso_msgs_submit(xorriso, 0,
   72               "Relative drive path given. Cannot determine working directory.",
   73                errno, "FAILURE", 0);
   74      {ret= -1; goto ex;}
   75    }
   76    ret= Sfile_add_to_path(abs_adr, path_pt, 0);
   77    if(ret <= 0)
   78      {ret= -1; goto ex;}
   79  }
   80 
   81  is_known_mmc= burn_drive_convert_fs_adr(path_pt, libburn_adr);
   82  does_exist= (stat(path_pt, &stbuf) != -1);
   83  Xorriso_process_msg_queues(xorriso,0);
   84 
   85  ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_whitelist, path_pt, 0);
   86  if(ret > 0)
   87    goto ok;
   88  ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_blacklist, path_pt, 0);
   89  if(ret < 0)
   90    goto ex;
   91  if(ret) {
   92    strcpy(xorriso->info_text, "Drive address ");
   93    Text_shellsafe(adr, xorriso->info_text, 1);
   94    strcat(xorriso->info_text,
   95           " rejected because: -drive_class 'banned' ");
   96    Text_shellsafe(Xorriso_get_pattern(xorriso, xorriso->drive_blacklist,
   97                                       ret - 1, 0),
   98                   xorriso->info_text, 1);
   99    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  100    {ret= 0; goto ex;}
  101  }
  102  /* if in greylist and not MMC and not stdio prefix: reject */
  103  if(is_known_mmc < 0)
  104    goto ex;
  105  if(adr == path_pt && !is_known_mmc) { /* no prefix, no MMC */
  106    ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_greylist, path_pt,0);
  107    if(ret < 0)
  108      goto ex;
  109    if(ret) {
  110      strcpy(xorriso->info_text, "Drive address ");
  111      Text_shellsafe(adr, xorriso->info_text, 1);
  112      strcat(xorriso->info_text, " rejected because: ");
  113      if(does_exist)
  114        strcat(xorriso->info_text, "not MMC");
  115      else
  116        strcat(xorriso->info_text, "not existing");
  117      strcat(xorriso->info_text, " and -drive_class 'caution' ");
  118      Text_shellsafe(Xorriso_get_pattern(xorriso,xorriso->drive_greylist,
  119                                         ret - 1, 0),
  120                     xorriso->info_text, 1);
  121      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  122      sprintf(xorriso->info_text,
  123              "If the address is a legitimate %s, prepend \"stdio:\"",
  124              does_exist ? "target" : "address for a new regular file");
  125      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
  126      {ret= 0; goto ex;}
  127    }
  128  }
  129 ok:;
  130  if(strncmp(adr, "mmc:", 4) == 0) {
  131    if(Sfile_str(result, path_pt, 0) <= 0)
  132      {ret= 0; goto ex;}
  133  } else if(adr == path_pt && is_known_mmc <= 0) {
  134    Sfile_str(result, "stdio:", 0);
  135    if(Sfile_str(result, adr, 1) <= 0)
  136      {ret= 0; goto ex;}
  137  } else {
  138    if(Sfile_str(result, adr, 0) <= 0)
  139      {ret= 0; goto ex;}
  140  }
  141  if(strncmp(result, "stdio:", 6)==0) {
  142    if(xorriso->ban_stdio_write) {
  143      strcpy(xorriso->info_text, "Drive address banned by -ban_stdio_write : ");
  144      Text_shellsafe(result, xorriso->info_text, 1);
  145      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  146      {ret= 0; goto ex;}
  147    }
  148  }
  149  ret= 1;
  150 ex:;
  151  Xorriso_free_meM(libburn_adr);
  152  Xorriso_free_meM(abs_adr);
  153  return(ret);
  154 }
  155 
  156 
  157 static int Xorriso_grasp_loaded_aaip(struct XorrisO *xorriso, IsoImage *volset,
  158                                      int flag)
  159 {
  160  int ret, change_pending_rec;
  161  IsoNode *root_node;
  162  size_t value_length;
  163  char *value= NULL;
  164  double num;
  165  struct FindjoB *job= NULL;
  166  struct stat dir_stbuf;
  167 
  168  /* To be re-instated at function end */ 
  169  change_pending_rec= xorriso->volset_change_pending;
  170 
  171  /* Look for isofs.st and put it into xorriso->isofs_st_in */
  172  root_node= (IsoNode *) iso_image_get_root(volset);
  173  ret= iso_node_lookup_attr(root_node, "isofs.st", &value_length, &value, 0);
  174  if(ret > 0) {
  175    if(value_length > 0) {
  176      sscanf(value, "%lf", &num);
  177      if(num > 0)
  178        xorriso->isofs_st_in= num;
  179    }
  180    free(value);
  181  }
  182 
  183  if(xorriso->do_hfsplus) {
  184    /* Bring isofs.hx to iso_hfsplus_xinfo_func,
  185       isofs.hb to IsoImage blessings
  186    */
  187    ret= Findjob_new(&job, "/", 0);
  188    if(ret<=0) {
  189      Xorriso_no_findjob(xorriso, "xorriso", 0);
  190      {ret= -1; goto ex;}
  191    }
  192    Findjob_set_action_target(job, 49, NULL, 0);
  193    ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/",
  194                       &dir_stbuf, 0, 0);
  195    if(ret <= 0)
  196      goto ex;
  197  }
  198 
  199  ret= 1;
  200 ex:;
  201  xorriso->volset_change_pending= change_pending_rec;
  202  Findjob_destroy(&job, 0);
  203  return(ret);
  204 }
  205 
  206 
  207 /* @param flag: bit0= set read speed
  208                 bit1= set write speed
  209 */
  210 int Xorriso_set_speed(struct XorrisO *xorriso, struct burn_drive *drive,
  211                       int read_speed, int write_speed, int flag)
  212 {
  213  int r_speed = 0, w_speed = 0, ret = 0, profile_no= 0;
  214  char profile_name[80];
  215 
  216  if((flag & 3) == 0)
  217    return(0);
  218  if(xorriso->read_speed == -2) {
  219    if(!(flag & 2))
  220      return(0);
  221  }
  222  if(flag & 1)
  223    r_speed= read_speed;
  224  if(flag & 2)
  225    w_speed= write_speed;
  226 
  227  ret= burn_disc_get_profile(drive, &profile_no, profile_name);
  228  if(ret <= 0)
  229    profile_no= 0;
  230  if((r_speed > 0 || w_speed > 0) && profile_no >= 0x10) {
  231    ret= burn_drive_set_speed_exact(drive, r_speed, w_speed);
  232    if(ret > 0)
  233      goto ex;
  234  }
  235  burn_drive_set_speed(drive, r_speed, w_speed);
  236  ret= 2;
  237 ex:;
  238  Xorriso_process_msg_queues(xorriso,0);
  239  return(ret);
  240 }
  241 
  242 
  243 /* @param flag bit0= acquire as isoburn input drive
  244                bit1= acquire as libburn output drive (as isoburn drive if bit0)
  245                bit2= regard overwritable media as blank
  246                bit3= if the drive is a regular disk file: truncate it to
  247                      the write start address
  248                bit5= do not print toc
  249                bit6= do not calm down drive after acquiring it
  250                bit7= re-assess rather than acquire:
  251                      Do not give up drives,
  252                      use isoburn_drive_aquire() with re-assessment bit
  253    @return <=0 failure , 1= ok
  254            2=success, but not writeable with bit1
  255            3=success, but not blank and not ISO with bit0
  256 */
  257 int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, char *show_adr,
  258                          int flag)
  259 {
  260  int ret, hret, not_writeable= 0, has_what, aquire_flag, load_lba, ext;
  261  int lba, track, session, params_flag, adr_mode, read_ret, start_lba;
  262  int truncate_mode;
  263  uint32_t size, offst;
  264  struct burn_drive_info *dinfo= NULL, *out_dinfo= NULL, *in_dinfo= NULL;
  265  struct burn_drive *drive= NULL, *out_drive= NULL, *in_drive= NULL;
  266  enum burn_disc_status state;
  267  IsoImage *volset = NULL;
  268  struct isoburn_read_opts *ropts= NULL;
  269  char *libburn_adr= NULL, *off_adr= NULL, *boot_fate, *sev;
  270  char volid[33], *adr_data= NULL, *adr_pt;
  271 
  272  Xorriso_alloc_meM(libburn_adr, char, SfileadrL);
  273  Xorriso_alloc_meM(off_adr, char, SfileadrL);
  274  Xorriso_alloc_meM(adr_data, char, 163);
  275 
  276  if(show_adr == NULL) {
  277    show_adr= adr;
  278    ret= burn_drive_convert_fs_adr(adr, off_adr);
  279    if(ret > 0)
  280      adr= off_adr;
  281  }
  282 
  283  if((flag&3)==0) { 
  284    sprintf(xorriso->info_text, 
  285          "XORRISOBURN program error : Xorriso_aquire_drive bit0+bit1 not set");
  286    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
  287    {ret= -1; goto ex;}
  288  }
  289  if(!(flag & 128)) {
  290    ret= Xorriso_give_up_drive(xorriso, (flag&3)|8);
  291    if(ret<=0)
  292      goto ex;
  293  }
  294  if(flag & 1) 
  295    xorriso->isofs_st_out= time(0) - 1;
  296 
  297  ret= Xorriso_auto_driveadr(xorriso, adr, libburn_adr, 0);
  298  if(ret <= 0)
  299    goto ex;
  300  if(strcmp(libburn_adr,"stdio:/dev/fd/1")==0) {
  301    if(xorriso->dev_fd_1<0) {
  302      sprintf(xorriso->info_text,
  303      "-*dev \"stdio:/dev/fd/1\" was not a start argument. Cannot use it now.");
  304      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  305      {ret= 0; goto ex;}
  306    } else {
  307      sprintf(libburn_adr, "stdio:/dev/fd/%d", xorriso->dev_fd_1);
  308    }
  309  }
  310 
  311  if(flag & 128) {
  312    if(flag & 1)
  313      Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive, "", 16);
  314    if(flag & 2)
  315      Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive, "", 2 | 16);
  316    if(in_dinfo != NULL && (out_dinfo == NULL || out_dinfo == in_dinfo)) {
  317      dinfo= in_dinfo;
  318      if(flag & 2) {
  319        xorriso->outdev_is_exclusive= xorriso->indev_is_exclusive;
  320        xorriso->outdev_access= xorriso->indev_access;
  321      }
  322    } else if(out_dinfo != NULL && in_dinfo == NULL) {
  323      dinfo= out_dinfo;
  324      if(flag & 1) {
  325        xorriso->indev_is_exclusive= xorriso->outdev_is_exclusive;
  326        xorriso->indev_access= xorriso->outdev_access;
  327      }
  328    } else if(out_dinfo != NULL || in_dinfo != NULL) {
  329      sprintf(xorriso->info_text,
  330              "Two different drives shall be re-assed in one call");
  331      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
  332      {ret= 0; goto ex;}
  333    } else {
  334      sprintf(xorriso->info_text, "No drive acquired on re-assessment");
  335      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
  336      {ret= 0; goto ex;}
  337    }
  338  } else if((flag&3)==1 && xorriso->out_drive_handle!=NULL) {
  339    ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
  340                          "on attempt to compare new indev with outdev", 2);
  341    if(ret<=0)
  342      goto ex;
  343    ret= burn_drive_equals_adr(out_drive, libburn_adr, 1);
  344    if(ret==1) {
  345      dinfo= out_dinfo;
  346      xorriso->indev_is_exclusive= xorriso->outdev_is_exclusive;
  347      xorriso->indev_access= xorriso->outdev_access;
  348    }
  349  } else if((flag&3)==2 && xorriso->in_drive_handle!=NULL) {
  350    ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive,
  351                          "on attempt to compare new outdev with indev", 0);
  352    if(ret<=0)
  353      goto ex;
  354    ret= burn_drive_equals_adr(in_drive, libburn_adr, 1);
  355    if(ret==1) {
  356      dinfo= in_dinfo;
  357      xorriso->outdev_is_exclusive= xorriso->indev_is_exclusive;
  358      xorriso->outdev_access= xorriso->indev_access;
  359    }
  360  }
  361 
  362  if(dinfo == NULL || (flag & 128)) {
  363    aquire_flag= 1 | ((flag&(8|4))>>1) | ((xorriso->toc_emulation_flag & 3)<<3);
  364    if(xorriso->toc_emulation_flag & 4)
  365      aquire_flag|= 128;
  366    if(xorriso->toc_emulation_flag & 8)
  367      aquire_flag|= 512;
  368    if(!(xorriso->do_aaip & 1))
  369      aquire_flag|= 32;
  370    if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (4 | 32))) {
  371      aquire_flag|= 64;
  372    } else if(xorriso->do_aaip & 1024) {
  373      aquire_flag|= 1024;
  374    }
  375    if(flag & 128)
  376      aquire_flag|= 256;
  377    burn_preset_device_open(xorriso->drives_exclusive |
  378                            (xorriso->linux_scsi_dev_family << 2), 0, 0);
  379    burn_allow_drive_role_4(1 | (xorriso->early_stdio_test & 14));
  380    ret= isoburn_drive_aquire(&dinfo, libburn_adr, aquire_flag);
  381    burn_preset_device_open(1 | (xorriso->linux_scsi_dev_family << 2), 0, 0);
  382    Xorriso_process_msg_queues(xorriso,0);
  383    if(ret<=0) {
  384      if(flag & 128)
  385        sprintf(xorriso->info_text,"Cannot re-assess drive '%s'", adr); 
  386      else
  387        sprintf(xorriso->info_text,"Cannot acquire drive '%s'", adr); 
  388      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  389      ret= 0; goto ex;
  390    }
  391    xorriso->use_immed_bit_default= burn_drive_get_immed(dinfo[0].drive) > 0 ?
  392                                    1 : -1;
  393    if(xorriso->use_immed_bit != 0)
  394      burn_drive_set_immed(dinfo[0].drive, xorriso->use_immed_bit > 0);
  395    state= isoburn_disc_get_status(dinfo[0].drive);
  396    ret= isoburn_get_img_partition_offset(dinfo[0].drive, &offst);
  397    if((state == BURN_DISC_APPENDABLE || state == BURN_DISC_FULL) && ret == 1) {
  398      sprintf(xorriso->info_text,
  399              "ISO image bears MBR with  -boot_image any partition_offset=%lu",
  400              (unsigned long) offst);
  401      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
  402    }
  403 
  404    if(flag&1)
  405      if(xorriso->image_start_mode&(1u<<31)) /* used up setting */
  406        xorriso->image_start_mode= 0; /* no need to perform auto setting */
  407    if(flag & 1) {
  408      xorriso->indev_is_exclusive= xorriso->drives_exclusive;
  409      xorriso->indev_access= xorriso->drives_access;
  410    }
  411    if(flag & 2) {
  412      xorriso->outdev_is_exclusive= xorriso->drives_exclusive;
  413      xorriso->outdev_access= xorriso->drives_access;
  414    }
  415  }
  416  drive= dinfo[0].drive;
  417  volset= isoburn_get_attached_image(drive);
  418  if(volset != NULL) {
  419    ret= iso_image_set_truncate_mode(volset, 1, xorriso->file_name_limit);
  420    iso_image_unref(volset);
  421    volset= NULL;
  422    Xorriso_process_msg_queues(xorriso,0);
  423    if(ret < 0)
  424      {ret= 0; goto ex;}
  425  }
  426  state= isoburn_disc_get_status(drive);
  427  Xorriso_process_msg_queues(xorriso,0);
  428  if(flag&1) {
  429    if(xorriso->image_start_mode&(1u<<31)) /* used up setting */
  430      xorriso->image_start_mode&= ~0xffff; /* perform auto setting */
  431    if((xorriso->image_start_mode&(1<<30))) { /* if enabled at all */
  432      adr_pt= xorriso->image_start_value;
  433      adr_mode= xorriso->image_start_mode & 0xffff;
  434      if(adr_mode == 4 && strlen(adr_pt) <= 80) {
  435        /* Convert volid search expression into lba */
  436        params_flag= 0;
  437        ret= Xorriso__bourne_to_reg(xorriso->image_start_value, adr_data, 0);
  438        if(ret == 1)
  439          params_flag|= 4;
  440        ret= isoburn_get_mount_params(drive, 4, adr_data, &lba, &track,
  441                                      &session, volid, params_flag);
  442        Xorriso_process_msg_queues(xorriso,0);
  443        if(ret <= 0)
  444          goto ex;
  445        if(session <= 0 || track <= 0 || ret == 2) {
  446          Xorriso_msgs_submit(xorriso, 0,
  447                 "-load : Given address does not point to an ISO 9660 session",
  448                 0, "FAILURE", 0);
  449          ret= 0; goto ex;
  450        }
  451        sprintf(volid, "%d", lba);
  452        adr_pt= volid;
  453        adr_mode= 3;
  454      }
  455      ret= isoburn_set_msc1(drive, adr_mode, adr_pt,
  456                            !!(xorriso->image_start_mode & (1<<16)));
  457      if(ret<=0)
  458        goto ex;
  459      if(xorriso->image_start_mode&(1u<<31))
  460        xorriso->image_start_mode= 0; /* disable msc1 setting completely */
  461      else
  462        xorriso->image_start_mode|= (1u<<31); /* mark as used up */
  463    }
  464  }
  465  if(flag&1) {
  466    volset= isoburn_get_attached_image(drive);
  467    if(volset != NULL) { /* The image object is already created */
  468      iso_image_unref(volset);
  469      volset= NULL;
  470    }
  471  }
  472 
  473  if(flag&2) {
  474    xorriso->out_drive_handle= dinfo;
  475    if(Sfile_str(xorriso->outdev, show_adr, 0)<=0)
  476      {ret= -1; goto ex;}
  477    ret= burn_drive_convert_fs_adr(adr, xorriso->outdev_off_adr);
  478    if(ret <= 0)
  479      xorriso->outdev_off_adr[0]= 0;
  480    if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE) {
  481      sprintf(xorriso->info_text, "Disc status unsuitable for writing");
  482      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
  483      not_writeable= 1;
  484    }
  485  }
  486  if(flag&1) {
  487    xorriso->in_drive_handle= dinfo;
  488    if(Sfile_str(xorriso->indev, show_adr, 0)<=0)
  489      {ret= -1; goto ex;}
  490    ret= burn_drive_convert_fs_adr(adr, xorriso->indev_off_adr);
  491    if(ret <= 0)
  492      xorriso->indev_off_adr[0]= 0;
  493  } else if(flag&2) {
  494    if(xorriso->in_volset_handle==NULL) {
  495      /* No volume loaded: create empty one */
  496      ret= Xorriso_create_empty_iso(xorriso, 0);
  497      if(ret<=0)
  498        goto ex;
  499    } else {
  500      iso_image_ref((IsoImage *) xorriso->in_volset_handle);
  501      start_lba= -1;
  502      ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive,
  503                         "on attempt to attach ISO image object to outdev", 16);
  504      if(ret > 0)
  505        start_lba= isoburn_get_attached_start_lba(in_drive);
  506      ret= isoburn_attach_image(drive, (IsoImage *) xorriso->in_volset_handle);
  507      if(ret<=0) {
  508        sprintf(xorriso->info_text,
  509                "Failed to attach ISO image object to outdev");
  510        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
  511        {ret= -1; goto ex;}
  512      }
  513      if(start_lba >= 0)
  514        isoburn_attach_start_lba(drive, lba, 0);
  515    }
  516    if(!(flag&32))
  517      Xorriso_toc(xorriso, 1 | 2 | 8);
  518    {ret= 1+not_writeable; goto ex;}
  519  }
  520 
  521  if(xorriso->in_volset_handle!=NULL)
  522    iso_image_unref((IsoImage *) xorriso->in_volset_handle);
  523  xorriso->in_volset_handle= NULL;
  524  Sectorbitmap_destroy(&(xorriso->in_sector_map), 0);
  525  Xorriso_destroy_hln_array(xorriso, 0);
  526  Xorriso_destroy_di_array(xorriso, 0);
  527  xorriso->boot_count= 0;
  528  xorriso->system_area_clear_loaded=  
  529                     (strcmp(xorriso->system_area_disk_path, "/dev/zero") == 0);
  530 
  531  /* check for invalid state */
  532  if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE &&
  533     state != BURN_DISC_FULL) {
  534    sprintf(xorriso->info_text,
  535            "Disc status not blank and unsuitable for reading");
  536    sev= "FAILURE";
  537    if(xorriso->img_read_error_mode==2)
  538      sev= "FATAL";
  539    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0);
  540    Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2));
  541    ret= 3; goto ex;
  542  }
  543  /* fill read opts */ 
  544  ret= isoburn_ropt_new(&ropts, 0);
  545  if(ret<=0)
  546    goto ex;
  547 
  548  ret= Xorriso_set_data_cache(xorriso, ropts, xorriso->cache_num_tiles,
  549                              xorriso->cache_tile_blocks,
  550                              xorriso->cache_default);
  551  if(ret<=0)
  552    goto ex;
  553 
  554  ext= isoburn_ropt_noiso1999;
  555  if(xorriso->read_fs & 1)
  556    ext|= isoburn_ropt_norock;
  557  if(xorriso->read_fs & 2)
  558    ext|= isoburn_ropt_nojoliet;
  559  if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (1 | 4 | 32))
  560     && !(xorriso->do_md5 & 1) && !(xorriso->do_hfsplus)) 
  561    ext|= isoburn_ropt_noaaip;
  562  if(!(xorriso->do_aaip & 1)) 
  563    ext|= isoburn_ropt_noacl; 
  564  if(!(xorriso->do_aaip & 4))
  565    ext|= isoburn_ropt_noea; 
  566  if(xorriso->ino_behavior & 1)
  567    ext|= isoburn_ropt_noino;
  568  if(!(xorriso->do_md5 & 1))
  569    ext|= isoburn_ropt_nomd5;
  570  if(xorriso->do_md5 & 32)
  571    ext|= isoburn_ropt_nomd5tag;
  572  if(xorriso->ecma119_map == 0)
  573    ext|= isoburn_ropt_map_unmapped;
  574  else if(xorriso->ecma119_map == 2)
  575    ext|= isoburn_ropt_map_uppercase;
  576  else if(xorriso->ecma119_map == 3)
  577    ext|= isoburn_ropt_map_lowercase;
  578  else
  579    ext|= isoburn_ropt_map_stripped;
  580  if(xorriso->joliet_map == 0)
  581    ext|= isoburn_ropt_joliet_unmapped;
  582  else
  583    ext|= isoburn_ropt_joliet_stripped;
  584 
  585  isoburn_ropt_set_extensions(ropts, ext);
  586 
  587  isoburn_ropt_set_default_perms(ropts, (uid_t) 0, (gid_t) 0, (mode_t) 0555);
  588  isoburn_ropt_set_input_charset(ropts, xorriso->in_charset);
  589  isoburn_ropt_set_auto_incharset(ropts, !!(xorriso->do_aaip & 512));
  590  isoburn_ropt_set_displacement(ropts, xorriso->displacement,
  591                                       xorriso->displacement_sign);
  592  isoburn_ropt_set_truncate_mode(ropts, 1, xorriso->file_name_limit);
  593  
  594  Xorriso_set_image_severities(xorriso, 1); /* No DEBUG messages */
  595  Xorriso_pacifier_reset(xorriso, 0);
  596  isoburn_set_read_pacifier(drive, Xorriso__read_pacifier, (void *) xorriso);
  597 
  598  /* <<< Trying to work around too much tolerance on bad image trees.
  599         Better would be a chance to instruct libisofs what to do in
  600         case of image read errors. There is a risk to mistake other SORRYs.
  601  */
  602  if(xorriso->img_read_error_mode>0)
  603    iso_set_abort_severity("SORRY");
  604 
  605  if(state != BURN_DISC_BLANK) {
  606    ret= isoburn_disc_get_msc1(drive, &load_lba);
  607    if(ret > 0) {
  608      sprintf(xorriso->info_text,
  609              "Loading ISO image tree from LBA %d", load_lba);
  610      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); 
  611    }
  612    ret= Xorriso_assert_volid(xorriso, load_lba, 0);
  613    if(ret <= 0)
  614      goto ex;
  615  }
  616  Xorriso_set_speed(xorriso, drive, xorriso->read_speed, 0, 1);
  617  read_ret= ret= isoburn_read_image(drive, ropts, &volset);
  618 
  619  /* <<< Resetting to normal thresholds */
  620  if(xorriso->img_read_error_mode>0)
  621    Xorriso_set_abort_severity(xorriso, 0);
  622 
  623  if(ret<=0) {
  624    Xorriso_process_msg_queues(xorriso,0);
  625    Xorriso_set_image_severities(xorriso, 0);
  626    Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2));
  627    sprintf(xorriso->info_text,"Cannot read ISO image tree");
  628    sev= "FAILURE";
  629    if(xorriso->img_read_error_mode==2)
  630      sev= "FATAL";
  631    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0);
  632    if(read_ret == (int) ISO_SB_TREE_CORRUPTED && (xorriso->do_md5 & 1)) {
  633      Xorriso_msgs_submit(xorriso, 0,
  634 "This might be false MD5 alarm if an add-on session was written by growisofs.",
  635         0, "HINT", 0);
  636      Xorriso_msgs_submit(xorriso, 0,
  637       "In this case you get an ISO image tree by option -md5 'load_check_off'",
  638         0, "HINT", 0);
  639    } else if(xorriso->img_read_error_mode!=0) {
  640      Xorriso_msgs_submit(xorriso, 0, "You might get a partial or altered ISO image tree by option -error_behavior 'image_loading' 'best_effort' if -abort_on is set to be tolerant enough.",
  641                          0, "HINT", 0);
  642    }
  643 
  644 
  645    ret= 3; goto ex;
  646  }
  647  Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0,
  648                            "", 1); /* report end count */
  649  xorriso->in_volset_handle= (void *) volset;
  650  xorriso->in_sector_map= NULL;
  651  Xorriso_set_image_severities(xorriso, 0);
  652 
  653  /* Might have changed due to isofs.nt */
  654  iso_image_get_truncate_mode(volset, &truncate_mode,
  655                              &(xorriso->file_name_limit));
  656  Xorriso_process_msg_queues(xorriso,0);
  657 
  658  Xorriso_update_volid(xorriso, 0);
  659  strncpy(xorriso->application_id,
  660          un0(iso_image_get_application_id(volset)), 128);
  661  xorriso->application_id[128]= 0;
  662  strncpy(xorriso->publisher, un0(iso_image_get_publisher_id(volset)), 128);
  663  xorriso->publisher[128]= 0;
  664  strncpy(xorriso->system_id, un0(iso_image_get_system_id(volset)), 32);
  665  xorriso->system_id[32]= 0;
  666  strncpy(xorriso->volset_id, un0(iso_image_get_volset_id(volset)), 128);
  667  xorriso->volset_id[128]= 0;
  668  strncpy(xorriso->copyright_file,
  669          un0(iso_image_get_copyright_file_id(volset)), 37);
  670  xorriso->copyright_file[37]= 0;
  671  strncpy(xorriso->biblio_file, un0(iso_image_get_biblio_file_id(volset)), 37);
  672  xorriso->biblio_file[37]= 0;
  673  strncpy(xorriso->abstract_file,
  674          un0(iso_image_get_abstract_file_id(volset)), 37);
  675  xorriso->abstract_file[37]= 0;
  676 
  677  if(xorriso->out_drive_handle != NULL &&
  678     xorriso->out_drive_handle != xorriso->in_drive_handle) {
  679    start_lba= -1;
  680    ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive,
  681                         "on attempt to attach ISO image volset to outdev", 16);
  682    if(ret > 0)
  683      start_lba= isoburn_get_attached_start_lba(in_drive);
  684    ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
  685                          "on attempt to attach ISO image volset to outdev", 2);
  686    if(ret<=0)
  687      goto ex;
  688    iso_image_ref((IsoImage *) xorriso->in_volset_handle);
  689    isoburn_attach_image(out_drive, xorriso->in_volset_handle);
  690    if(start_lba >= 0)
  691      isoburn_attach_start_lba(out_drive, ret, 0);
  692  }
  693  Xorriso_process_msg_queues(xorriso,0);
  694  isoburn_ropt_get_size_what(ropts, &size, &has_what);
  695  xorriso->isofs_size= size;
  696  xorriso->isofs_has_what= has_what;
  697  isoburn_ropt_get_tree_loaded(ropts, &(xorriso->tree_loaded),
  698                               &(xorriso->rr_loaded));
  699 
  700  if(has_what & isoburn_ropt_has_el_torito) {
  701    if(xorriso->boot_image_bin_path[0])
  702      boot_fate= "replaced by new boot image";
  703    else if(xorriso->patch_isolinux_image & 1)
  704      boot_fate= "patched at boot info table";
  705    else if(xorriso->keep_boot_image)
  706      boot_fate= "kept unchanged";
  707    else
  708      boot_fate= "discarded";
  709    sprintf(xorriso->info_text,
  710          "Detected El-Torito boot information which currently is set to be %s",
  711          boot_fate);
  712    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); 
  713    Xorriso_record_boot_info(xorriso, 0);
  714  }
  715 
  716  if(flag & 1) {
  717    ret= Xorriso_grasp_loaded_aaip(xorriso, volset, 0);
  718    if(ret <= 0)
  719      goto ex;
  720  }
  721 
  722  if(!(flag&32)) {
  723    Xorriso_toc(xorriso, 1 | 8);
  724    if(xorriso->loaded_volid[0] != 0 &&
  725       (state == BURN_DISC_APPENDABLE || state == BURN_DISC_FULL)) {
  726        sprintf(xorriso->info_text,"Volume id    : '%s'\n",
  727                xorriso->loaded_volid);
  728        Xorriso_info(xorriso, 0);
  729    }
  730    if(strcmp(xorriso->loaded_volid, xorriso->volid) != 0 &&
  731       !xorriso->volid_default) {
  732      sprintf(xorriso->info_text, "New volume id: '%s'\n", xorriso->volid);
  733      Xorriso_info(xorriso, 0);
  734    }
  735  }
  736 
  737  ret= 1+not_writeable;
  738 ex:
  739  Xorriso_process_msg_queues(xorriso,0);
  740  if(ret<=0) {
  741    hret= Xorriso_give_up_drive(xorriso, (flag&3)|((flag&32)>>2));
  742    if(hret<ret)
  743      ret= hret;
  744  } else {
  745    if(drive != NULL && (xorriso->do_calm_drive & 1) && !(flag & 64))
  746      burn_drive_snooze(drive, 0); /* No need to make noise from start */
  747  }
  748  if(ropts!=NULL)
  749    isoburn_ropt_destroy(&ropts, 0);
  750  Xorriso_free_meM(off_adr);
  751  Xorriso_free_meM(libburn_adr);
  752  Xorriso_free_meM(adr_data);
  753  return(ret);
  754 }
  755 
  756 
  757 /* @param flag bit0=input drive
  758                bit1=output drive
  759                bit2=eject
  760                bit3=no info message or toc
  761 */
  762 int Xorriso_give_up_drive(struct XorrisO *xorriso, int flag)
  763 {
  764  int in_is_out_too, ret, do_eject;
  765  struct burn_drive_info *dinfo;
  766  struct burn_drive *drive;
  767  
  768  in_is_out_too= (xorriso->in_drive_handle == xorriso->out_drive_handle);
  769  if((flag&4) && in_is_out_too && (flag&(1|2))) {
  770    if((flag&3)!=3) {
  771      sprintf(xorriso->info_text,"Giving up for -eject whole -dev ");
  772      Text_shellsafe(xorriso->indev, xorriso->info_text, 1);
  773      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
  774    }
  775    flag|= 3; /* give up in/out drive to eject it */
  776  }
  777    
  778  if((flag&1) && xorriso->in_drive_handle != NULL) {
  779    Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
  780                              "on attempt to give up drive", 0);
  781 
  782    if(!in_is_out_too) {
  783      do_eject= !!(flag&4);
  784      if((flag & 4) && xorriso->indev_access == 0) {
  785        sprintf(xorriso->info_text,
  786              "Will not eject medium in readonly acquired input drive.");
  787        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
  788        do_eject= 0;
  789      }
  790      if(drive!=NULL)
  791        isoburn_drive_release(drive, do_eject);
  792      if(dinfo!=NULL)
  793        burn_drive_info_free(dinfo);
  794    }
  795    xorriso->in_drive_handle= NULL;
  796    xorriso->indev[0]= 0;
  797 
  798    if(xorriso->in_volset_handle!=NULL)
  799      iso_image_unref((IsoImage *) xorriso->in_volset_handle);
  800    xorriso->in_volset_handle= NULL;
  801    Sectorbitmap_destroy(&(xorriso->in_sector_map), 0);
  802    Xorriso_destroy_di_array(xorriso, 0);
  803    Xorriso_destroy_hln_array(xorriso, 0);
  804    xorriso->loaded_volid[0]= 0;
  805    xorriso->isofs_st_out= time(0) - 1;
  806    xorriso->isofs_st_in= 0;
  807    xorriso->volset_change_pending= 0;
  808    xorriso->no_volset_present= 0; 
  809    xorriso->loaded_boot_bin_lba= 0;
  810    xorriso->loaded_boot_cat_path[0]= 0;
  811    xorriso->boot_count= 0;
  812    in_is_out_too= 0;
  813  }
  814  if((flag&2) && xorriso->out_drive_handle!=NULL) {
  815    do_eject= !!(flag&4);
  816    if((flag & 4) && xorriso->outdev_access == 0) {
  817      sprintf(xorriso->info_text,
  818              "Will not eject medium in readonly acquired drive.");
  819      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
  820      do_eject= 0;
  821    }
  822    ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
  823                                   "on attempt to give up drive", 2);
  824    if(ret >= 0 && !in_is_out_too) {
  825      if(drive!=NULL)
  826        isoburn_drive_release(drive, do_eject);
  827      if(dinfo!=NULL)
  828        burn_drive_info_free(dinfo);
  829    }
  830    xorriso->out_drive_handle= NULL;
  831    xorriso->outdev[0]= 0;
  832    xorriso->outdev_off_adr[0]= 0;
  833  } else if((flag&1) && xorriso->out_drive_handle!=NULL) {
  834    ret= Xorriso_create_empty_iso(xorriso, 0);
  835    if(ret<=0)
  836      return(ret);
  837    if(!(flag&8)) {
  838      sprintf(xorriso->info_text,
  839              "Only the output drive remains. Created empty ISO image.\n");
  840      Xorriso_info(xorriso, 0);
  841      Xorriso_toc(xorriso, 1 | 2 | 8);
  842    }
  843  }
  844  Xorriso_process_msg_queues(xorriso,0);
  845  return(1);
  846 }
  847 
  848 
  849 int Xorriso_may_burn(struct XorrisO *xorriso, int flag)
  850 {
  851 
  852  if(xorriso->outdev_access == 1)
  853    return(1);
  854  sprintf(xorriso->info_text, "The output drive was acquired readonly.");
  855  Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  856  sprintf(xorriso->info_text, "Possible remedy: -drive_access \"exclusive:unrestricted\".");
  857  strcat(xorriso->info_text," Then give up and re-acquire the drive.");
  858  Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
  859  if(!xorriso->outdev_is_exclusive) {
  860    sprintf(xorriso->info_text, "If you insist in -drive_access \"shared:unrestricted\", first read man xorriso about the risks.");
  861    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
  862  }
  863  return(0);
  864 }
  865 
  866 
  867 /* @param flag bit1=report about output drive rather than input drive
  868                bit2=do not try to read ISO heads
  869 */
  870 int Xorriso_toc_to_string(struct XorrisO *xorriso, char **toc_text, int flag)
  871 {
  872  int ret, stack_handle, toc_ret, l;
  873  struct Xorriso_lsT *results= NULL, *infos= NULL, *lpt;
  874 
  875  *toc_text= NULL;
  876  ret= Xorriso_push_outlists(xorriso, &stack_handle, 1);
  877  if(ret <= 0)
  878    goto ex;
  879  toc_ret= Xorriso_toc(xorriso, flag & (2 | 4));
  880  ret= Xorriso_pull_outlists(xorriso, stack_handle, &results, &infos, 0);
  881  if(ret <= 0)
  882    goto ex;
  883  if(toc_ret <= 0)
  884    {ret= toc_ret; goto ex;}
  885  l= 0;
  886  for(lpt= results; lpt != NULL; lpt= Xorriso_lst_get_next(lpt, 0))
  887    l+= strlen(Xorriso_lst_get_text(lpt, 0));
  888  *toc_text= calloc(l + 1, 1);
  889  l= 0;
  890  for(lpt= results; lpt != NULL; lpt= Xorriso_lst_get_next(lpt, 0)) {
  891    strcpy((*toc_text) + l, Xorriso_lst_get_text(lpt, 0));
  892    l+= strlen(Xorriso_lst_get_text(lpt, 0));
  893  }
  894 ex:;
  895  Xorriso_lst_destroy_all(&results, 0);
  896  Xorriso_lst_destroy_all(&infos, 0);
  897  return(ret);
  898 }
  899 
  900 
  901 /* @param flag bit0+1= what to give up and/or re-assess in what role
  902                        0=give up outdev
  903                        1=give up indev if not outdev, re-assess outdev as indev
  904                        2=re-assess outdev as outdev
  905                        3=give up indev if not outdev, re-assess outdev as dev
  906 */
  907 int Xorriso_reaquire_outdev(struct XorrisO *xorriso, int flag)
  908 {
  909  int ret, aq_flag;
  910  char *drive_name= NULL, *off_name= NULL;
  911 
  912  Xorriso_alloc_meM(drive_name, char, SfileadrL);
  913  Xorriso_alloc_meM(off_name, char, SfileadrL);
  914  aq_flag= flag&3;
  915  strcpy(drive_name, xorriso->outdev);
  916  if(xorriso->outdev_off_adr[0])
  917    strcpy(off_name, xorriso->outdev_off_adr);
  918  else
  919    strcpy(off_name, drive_name);
  920 
  921  if(aq_flag == 0) {
  922    Xorriso_give_up_drive(xorriso, 2);
  923    sprintf(xorriso->info_text,"Gave up -outdev ");
  924    Text_shellsafe(xorriso->indev, xorriso->info_text, 1);
  925    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
  926    {ret= 1; goto ex;}
  927  }
  928 
  929  /* Only give up indev, and only if it is not outdev */;
  930  if(xorriso->in_drive_handle != xorriso->out_drive_handle &&
  931     xorriso->in_drive_handle != NULL && (aq_flag & 1))
  932    Xorriso_give_up_drive(xorriso, 1 | 8);
  933  sprintf(xorriso->info_text,"Re-assessing -outdev ");
  934  Text_shellsafe(drive_name, xorriso->info_text, 1);
  935  if(strcmp(drive_name, off_name) != 0) {
  936    strcat(xorriso->info_text, "  (");
  937    Text_shellsafe(off_name, xorriso->info_text, 1);
  938    strcat(xorriso->info_text, ")");
  939  }
  940  Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
  941 
  942  /* Re-assess outdev */
  943  ret= Xorriso_aquire_drive(xorriso, off_name, drive_name, aq_flag | 128); 
  944  if(ret<=0) {
  945    sprintf(xorriso->info_text,"Could not re-assess -outdev ");
  946    Text_shellsafe(drive_name, xorriso->info_text, 1);
  947    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
  948    goto ex;
  949  }
  950 
  951  ret= 1;
  952 ex:;
  953  Xorriso_free_meM(drive_name);
  954  Xorriso_free_meM(off_name);
  955  return(ret);
  956 }
  957 
  958 
  959 /* @param flag
  960                bit3=report to info channel (else to result channel)
  961 */
  962 int Xorriso_toc_line(struct XorrisO *xorriso, int flag)
  963 {
  964  if(!(flag & 8)) {
  965    Xorriso_result(xorriso,0);
  966    return(1);
  967  }
  968  strcpy(xorriso->info_text, xorriso->result_line);
  969  Xorriso_info(xorriso, 0);
  970  return(1);
  971 }
  972 
  973 
  974 /* @param flag
  975                bit1=report about output drive
  976                bit3=report to info channel (else to result channel)
  977                bit4=do no report failure if no drive acquired
  978 */
  979 int Xorriso_media_product(struct XorrisO *xorriso, int flag)
  980 {
  981  int ret, profile_no;
  982  struct burn_drive_info *dinfo;
  983  struct burn_drive *drive;
  984  char *product_id= NULL, *media_code1= NULL, *media_code2= NULL;
  985  char *book_type= NULL, *manuf= NULL, profile_name[80], *respt;
  986 
  987  respt= xorriso->result_line;
  988 
  989  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
  990                                 "on attempt to print media product info",
  991                                  flag & (2 | 16));
  992  if(ret <= 0)
  993    return(ret);
  994  ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2,
  995                              &book_type, 0);
  996  if(ret > 0) {
  997    ret= burn_disc_get_profile(drive, &profile_no, profile_name);
  998    if(ret <= 0)
  999      return(ret);
 1000    sprintf(respt, "Media product: %s , ", product_id);
 1001    manuf= burn_guess_manufacturer(profile_no, media_code1, media_code2, 0);
 1002    if(manuf != NULL) {
 1003      if(strncmp(manuf, "Unknown ", 8) == 0)
 1004        sprintf(respt + strlen(respt), "(not found in manufacturer list)\n");
 1005      else
 1006        sprintf(respt + strlen(respt), "%s\n", manuf);
 1007    } else
 1008      sprintf(respt + strlen(respt), "(error during manufacturer lookup)\n");
 1009    free(product_id);
 1010    free(media_code1);
 1011    free(media_code2);
 1012    if(book_type != NULL)
 1013      free(book_type);
 1014    if(manuf != NULL)
 1015      free(manuf);
 1016    Xorriso_toc_line(xorriso, flag & 8);
 1017  }
 1018  Xorriso_process_msg_queues(xorriso,0);
 1019 
 1020  return(1);
 1021 }
 1022 
 1023 
 1024 /* @param flag bit0=short report form
 1025                bit1=report about output drive
 1026                bit2=do not try to read ISO heads
 1027                bit3=report to info channel (else to result channel)
 1028                bit4=do no report failure if no drive acquired
 1029                bit5=only report "Drive current" and "Drive type"
 1030                bit6=report "Media product" with bit0
 1031                bit7=only report "Drive current"
 1032 */
 1033 int Xorriso_toc(struct XorrisO *xorriso, int flag)
 1034 {
 1035  int num_sessions= 0, num_tracks= 0, lba= 0, nwa= -1, ret;
 1036  int track_count= 0, session_no, track_no, profile_no= -1, track_size;
 1037  int session_size, first_track_start= 0;
 1038  int num_session_data, num_session_other;
 1039  int num_data= 0, other_data= 0, is_data= 0;
 1040  int is_inout_drive= 0, drive_role, status, num_formats, emul_lba;
 1041  int not_recognizable= 0, start_lba, end_lba;
 1042  int sessions_seen, open_sessions= 0, have_real_open_session= 0;
 1043  char profile_name[80],*respt,*devadr, *typetext= "";
 1044  struct burn_toc_entry toc_entry;
 1045  struct burn_drive_info *dinfo;
 1046  struct burn_multi_caps *caps= NULL;
 1047  struct burn_drive *drive;
 1048  enum burn_disc_status s;
 1049  char mem_text[80], *num_free_text;
 1050  off_t start_byte= 0, num_free= 0, size;
 1051  unsigned dummy;
 1052  struct isoburn_toc_disc *disc= NULL;
 1053  struct isoburn_toc_session **sessions;
 1054  struct isoburn_toc_track **tracks;
 1055  int image_blocks= 0;
 1056  char volume_id[33];
 1057  struct burn_toc_entry next_toc_entry;
 1058  int disk_category, part_version, num_layers, num_blocks;
 1059  char *book_name;
 1060  int num_data_from_format= 0;
 1061  char *sno = NULL;
 1062  int sno_len, i, is_bdr_pow= 0;
 1063 
 1064  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 1065                                 "on attempt to print Table Of Content",
 1066                                  flag & (2 | 16));
 1067  if(ret<=0)
 1068    {ret= 0; goto ex;}
 1069 
 1070  respt= xorriso->result_line;
 1071 
 1072  if(strcmp(xorriso->indev, xorriso->outdev)==0)
 1073    is_inout_drive= 1;
 1074  if(flag&2)
 1075    devadr= xorriso->outdev;
 1076  else
 1077    devadr= xorriso->indev;
 1078  sprintf(respt, "Drive current: %s '%s'\n",
 1079          (is_inout_drive ? "-dev" : (flag&2 ? "-outdev" : "-indev")),
 1080          devadr);
 1081  Xorriso_toc_line(xorriso, flag & 8);
 1082  if(flag & 128)
 1083    {ret= 1; goto ex;}
 1084  /* Report -drive_access if non-default or if long form */
 1085  respt[0]= 0;
 1086  if(flag & 2) {
 1087    if(xorriso->outdev_is_exclusive == 0 || xorriso->outdev_access == 0 ||
 1088       !(flag & 33)) {
 1089      sprintf(respt, "Drive access : %s:%s\n",
 1090              xorriso->outdev_is_exclusive ? "exclusive" : "shared",
 1091              xorriso->outdev_access == 0 ? "readonly" : "unrestricted");
 1092      }
 1093  } else {
 1094    if(xorriso->indev_is_exclusive == 0 || xorriso->indev_access == 0 ||
 1095       !(flag & 33)) {
 1096      sprintf(respt, "Drive access : %s:%s\n",
 1097              xorriso->indev_is_exclusive ? "exclusive" : "shared",
 1098              xorriso->indev_access == 0 ? "readonly" : "unrestricted");
 1099    }
 1100  }
 1101  if(respt[0])
 1102    Xorriso_toc_line(xorriso, flag & 8);
 1103  sprintf(respt, "Drive type   : vendor '%s' product '%s' revision '%s'\n",
 1104         dinfo[0].vendor, dinfo[0].product, dinfo[0].revision);
 1105  if((flag & 32) || !(flag & 1))
 1106    Xorriso_toc_line(xorriso, flag & 8);
 1107  if(flag & 32)
 1108    {ret= 1; goto ex;}
 1109 
 1110  if(!(flag & 1)) {
 1111    burn_drive_get_serial_no(drive, &sno, &sno_len);
 1112    if(sno_len > 0) {
 1113      sprintf(respt, "Drive id     : '%s'\n", sno);
 1114      Xorriso_toc_line(xorriso, flag & 8);
 1115    }
 1116    if(sno != NULL)
 1117      free(sno);
 1118    sno= NULL;
 1119  }
 1120  
 1121  ret= burn_disc_get_profile(drive, &profile_no, profile_name);
 1122  s= isoburn_disc_get_status(drive);
 1123  if(profile_no == 0x0002 && s == BURN_DISC_EMPTY)
 1124    profile_no= 0;
 1125  is_bdr_pow= burn_drive_get_bd_r_pow(drive);
 1126  sprintf(respt, "Media current: ");
 1127  drive_role= burn_drive_get_drive_role(drive);
 1128  if (profile_no > 0 && ret > 0) {
 1129    if (profile_name[0])
 1130      sprintf(respt+strlen(respt), "%s", profile_name);
 1131    else
 1132      sprintf(respt+strlen(respt), "%4.4Xh", profile_no);
 1133    if(is_bdr_pow)
 1134      sprintf(respt+strlen(respt), ", Pseudo Overwrite formatted");
 1135    else if(drive_role==2)
 1136      sprintf(respt+strlen(respt), ", overwriteable");
 1137    else if(drive_role == 4)
 1138      sprintf(respt+strlen(respt), ", random read-only");
 1139    else if(drive_role == 5)
 1140      sprintf(respt+strlen(respt), ", random write-only");
 1141    else if(drive_role==0 || drive_role==3)
 1142      sprintf(respt+strlen(respt), ", sequential");
 1143    strcat(respt, "\n");
 1144  } else {
 1145     sprintf(respt+strlen(respt), "is not recognizable\n");
 1146     not_recognizable= 1;
 1147  }
 1148  Xorriso_toc_line(xorriso, flag & 8);
 1149 
 1150  if((flag & 64) || !(flag & 1)) {
 1151    Xorriso_media_product(xorriso, flag & (2 | 8 | 16));
 1152    if(xorriso->request_to_abort)
 1153      {ret= 1; goto ex;}
 1154  }
 1155 
 1156  sprintf(respt, "Media status : ");
 1157  if(is_bdr_pow) {
 1158    sprintf(respt+strlen(respt), "is unsuitable , is POW formatted");
 1159  } else if (s == BURN_DISC_FULL) {
 1160    if(not_recognizable)
 1161      sprintf(respt+strlen(respt), "is not recognizable\n");
 1162    else
 1163      sprintf(respt+strlen(respt), "is written , is closed");
 1164  } else if (s == BURN_DISC_APPENDABLE) {
 1165    sprintf(respt+strlen(respt), "is written , is appendable");
 1166  } else if (s == BURN_DISC_BLANK) {
 1167    sprintf(respt+strlen(respt), "is blank");
 1168  } else if (s == BURN_DISC_EMPTY)
 1169    sprintf(respt+strlen(respt), "is not present");
 1170  else
 1171    sprintf(respt+strlen(respt), "is not recognizable");
 1172  if(s == BURN_DISC_APPENDABLE || s == BURN_DISC_BLANK) {
 1173    ret= burn_disc_next_track_is_damaged(drive, 0);
 1174    if(ret & 1)
 1175      sprintf(respt+strlen(respt), " , but next track is damaged");
 1176    else if(ret & 2)
 1177      sprintf(respt+strlen(respt), " , but no writable address");
 1178    else if(profile_no == 0x14) { /* DVD-RW sequential */
 1179      ret= burn_disc_get_multi_caps(drive, BURN_WRITE_TAO, &caps, 0);
 1180      if(ret == 0)
 1181        sprintf(respt+strlen(respt), " , but will need -close on");
 1182      if(caps != NULL)
 1183        burn_disc_free_multi_caps(&caps);
 1184    } else if(profile_no == 0x15) { /* DVD-RW DL */
 1185      sprintf(respt+strlen(respt), " , but will need -close \"on\"");
 1186    }
 1187  }
 1188  strcat(respt, "\n");
 1189  Xorriso_toc_line(xorriso, flag & 8);
 1190 
 1191  if((s == BURN_DISC_FULL || s == BURN_DISC_APPENDABLE ||
 1192      s == BURN_DISC_BLANK) && !(flag & 1)) {
 1193    burn_drive_get_media_sno(drive, &sno, &sno_len);
 1194    if(sno_len > 0) {
 1195      sprintf(respt, "Media id     : ");
 1196      respt+= strlen(respt);
 1197      for(i= 0; i < sno_len && i < 1024; i++) {
 1198        sprintf(respt, "%2.2X", (unsigned int) ((unsigned char *) sno)[i]);
 1199        respt+= 2;
 1200      }
 1201      if(i < sno_len)
 1202        strcat(respt, "...");
 1203      strcat(respt, "\n");
 1204      Xorriso_toc_line(xorriso, flag & 8);
 1205    }
 1206    if(sno != NULL)
 1207      free(sno);
 1208    sno= NULL;
 1209    respt= xorriso->result_line;
 1210 
 1211    ret= burn_get_read_capacity(drive, &num_data, 0);
 1212    if(ret != 1 || s == BURN_DISC_BLANK)
 1213      num_data= 0;
 1214    num_free= isoburn_disc_available_space(drive, NULL) / 2048; 
 1215    nwa= -1;
 1216    if (s == BURN_DISC_APPENDABLE) {
 1217      ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
 1218      if(ret <= 0)
 1219        nwa= -1;
 1220    } else if(s == BURN_DISC_BLANK) {
 1221      ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
 1222      if(ret == 1) {
 1223        num_free+= nwa;
 1224        nwa= 0;
 1225      }
 1226    }
 1227    lba= num_data + num_free;
 1228    if(nwa >= 0) {
 1229      lba= nwa + num_free;
 1230      if(nwa < num_data)
 1231        num_data= nwa;
 1232    }
 1233 
 1234    /* If closed CD-RW : obtain ATIP lead out address */
 1235    if(profile_no == 0x0a) {
 1236      ret= burn_disc_read_atip(drive);
 1237      if(ret < 0)
 1238        goto ex;
 1239      ret= burn_drive_get_start_end_lba(drive, &start_lba, &end_lba, 0);
 1240      if(s == BURN_DISC_FULL && ret == 1) {
 1241        lba= end_lba - 2;
 1242      } else {
 1243        if(ret == 1 && end_lba  - 2 > lba) {
 1244          sprintf(xorriso->info_text,
 1245                  "ATIP end_lba %d > overall %d", end_lba, lba);
 1246          Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 1247        }
 1248      }
 1249    } else if(profile_no == 0x14) {
 1250      ret= burn_disc_get_phys_format_info(drive, &disk_category,
 1251                                          &book_name, &part_version,
 1252                                          &num_layers, &num_blocks, 0);
 1253      if(ret == 1 && num_blocks > lba)
 1254        lba= num_blocks;
 1255    }
 1256 
 1257    if(drive_role == 4 || is_bdr_pow)
 1258      num_free_text = "unused";
 1259    else
 1260      num_free_text = "writable";
 1261    sprintf(respt, "Media blocks : %d readable , %d %s , %d overall\n",
 1262                   num_data, (int) num_free, num_free_text, lba);
 1263    Xorriso_toc_line(xorriso, flag & 8);
 1264  }
 1265 
 1266  if(s == BURN_DISC_BLANK) {
 1267    sprintf(respt, "Media summary: 0 sessions, 0 data blocks, 0 data");
 1268    num_free= isoburn_disc_available_space(drive, NULL); 
 1269    Sfile_scale((double) num_free, mem_text,5,1e4,1);
 1270    sprintf(respt+strlen(respt), ", %s free\n", mem_text);
 1271    Xorriso_toc_line(xorriso, flag & 8);
 1272  }
 1273  if(s != BURN_DISC_FULL && s != BURN_DISC_APPENDABLE)
 1274    {ret= 1; goto ex;}
 1275  if(xorriso->request_to_abort)
 1276    {ret= 1; goto ex;}
 1277  if(is_bdr_pow) {
 1278    sprintf(respt,
 1279            "Media summary: unsuitable Pseudo Overwrite formatted BD-R\n");
 1280    Xorriso_toc_line(xorriso, flag & 8);
 1281    {ret= 1; goto ex;}
 1282  }
 1283 
 1284  if(!(flag & 2))
 1285    Xorriso_show_boot_info(xorriso, 1 | (flag & 8) | ((flag & 1) << 1));
 1286 
 1287  if(xorriso->isofs_size > 0 && !(flag & 3)) {
 1288    sprintf(respt, "ISO offers   :%s%s%s%s\n",
 1289                   xorriso->isofs_has_what & 1 ? " Rock_Ridge" : "",
 1290                   xorriso->isofs_has_what & 2 ? " Joliet" : "",
 1291                   xorriso->isofs_has_what & 4 ? " ISO_9660_1999" : "",
 1292                   xorriso->isofs_has_what & 7 ? "" : " Only_ECMA_119");
 1293    Xorriso_toc_line(xorriso, flag & 8);
 1294    sprintf(respt, "ISO loaded   : %s\n",
 1295                   xorriso->tree_loaded == 1 ? "Joliet" :
 1296                   xorriso->tree_loaded == 2 ? "ISO_9660_1999" :
 1297                   xorriso->rr_loaded > 0 ? "Rock_Ridge" : "Only_ECMA_119");
 1298    Xorriso_toc_line(xorriso, flag & 8);
 1299  }
 1300 
 1301  disc= isoburn_toc_drive_get_disc(drive);
 1302  if(flag & 4)
 1303    sprintf(respt, "TOC layout   : %3s , %9s , %10s\n",
 1304            "Idx", "sbsector", "Size");
 1305  else
 1306    sprintf(respt, "TOC layout   : %3s , %9s , %10s , %s\n",
 1307            "Idx", "sbsector", "Size", "Volume Id");
 1308  if(!(flag&1))
 1309    Xorriso_toc_line(xorriso, flag & 8);
 1310 
 1311  if (disc==NULL) {
 1312    Xorriso_process_msg_queues(xorriso,0);
 1313    if(drive_role == 5 && s == BURN_DISC_APPENDABLE) {
 1314      ret= burn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
 1315      if(ret != 1)
 1316        lba= 0;
 1317    } else {
 1318      ret= isoburn_get_min_start_byte(drive, &start_byte, 0);
 1319      nwa= start_byte / 2048;
 1320      if(ret<=0) {
 1321        Xorriso_process_msg_queues(xorriso,0);
 1322        if(flag&1)
 1323          {ret= 1; goto ex;}
 1324        sprintf(xorriso->info_text, "Cannot obtain Table Of Content");
 1325        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 1326        {ret= 0; goto ex;}
 1327      }
 1328    }
 1329 
 1330    /* fabricate TOC */
 1331    typetext= "Other session";
 1332    if(flag & 4) {
 1333      ret= 0;
 1334      typetext= "Session      ";
 1335    } else
 1336      ret= isoburn_read_iso_head(drive, 0, &image_blocks, volume_id, 1);
 1337    if(ret>0) {
 1338      sprintf(respt, "ISO session  : %3d , %9d , %9ds , %s\n",
 1339              1, 0, image_blocks, volume_id);
 1340      nwa= image_blocks;
 1341    } else {
 1342      ret= burn_disc_get_formats(drive, &status, &size, &dummy,
 1343                                 &num_formats);
 1344      if(ret <= 0 || status != BURN_FORMAT_IS_FORMATTED)
 1345        size= 0;
 1346      if(size <= 0) {
 1347        ret= burn_get_read_capacity(drive, &num_data, 0);
 1348        if(ret == 1)
 1349          size= ((off_t) num_data) * (off_t) 2048; 
 1350      } else {
 1351        num_data_from_format= 1;
 1352      }
 1353      nwa= lba + size / 2048;
 1354      num_data= nwa - lba;
 1355      sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
 1356              typetext, 1, lba, num_data);
 1357    } 
 1358    if(!(flag&1))
 1359      Xorriso_toc_line(xorriso, flag & 8);
 1360    num_sessions= 1;
 1361  } else {
 1362    num_data= other_data= 0;
 1363    sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
 1364    open_sessions= isoburn_toc_disc_get_incmpl_sess(disc);
 1365    for (session_no= 0;
 1366         session_no < num_sessions + open_sessions &&
 1367         !(xorriso->request_to_abort);
 1368         session_no++) {
 1369      num_session_data= num_session_other= 0;
 1370      tracks= isoburn_toc_session_get_tracks(sessions[session_no], &num_tracks);
 1371      if (tracks == NULL || num_tracks <= 0)
 1372    continue;
 1373      if(session_no == num_sessions + open_sessions - 1 && open_sessions > 0)
 1374        have_real_open_session= 1;
 1375      for(track_no= 0; track_no<num_tracks && !(xorriso->request_to_abort);
 1376          track_no++) {
 1377        track_count++;
 1378        is_data= 0;
 1379        isoburn_toc_track_get_entry(tracks[track_no], &toc_entry);
 1380        if((toc_entry.control & 7) >= 4) /* data track */
 1381          is_data= 1;
 1382        if (toc_entry.extensions_valid & 1) {
 1383          /* DVD extension valid */
 1384          lba= toc_entry.start_lba;
 1385          track_size= toc_entry.track_blocks;
 1386        } else {
 1387          lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
 1388                               toc_entry.pframe);
 1389          if(track_no==num_tracks-1) {
 1390            isoburn_toc_session_get_leadout_entry(sessions[session_no],
 1391                                                  &next_toc_entry);
 1392          } else {
 1393            isoburn_toc_track_get_entry(tracks[track_no+1], &next_toc_entry);
 1394          }
 1395          track_size= burn_msf_to_lba(next_toc_entry.pmin, next_toc_entry.psec,
 1396                                      next_toc_entry.pframe) - lba;
 1397        }
 1398        if((flag & (1 | 4)) || !is_data) {
 1399          ret= 0;
 1400        } else {
 1401          ret= isoburn_toc_track_get_emul(tracks[track_no], &emul_lba,
 1402                                          &image_blocks, volume_id, 0);
 1403          if(ret <= 0)
 1404            ret= isoburn_read_iso_head(drive, lba, &image_blocks, volume_id, 1);
 1405          if(image_blocks > track_size) {
 1406            sprintf(xorriso->info_text,
 1407               "Session %d bears ISO image size %ds larger than track size %ds",
 1408               session_no + 1, image_blocks, track_size);
 1409            Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING",
 1410                                0);
 1411            image_blocks= track_size;
 1412          }
 1413        }
 1414        if(session_no >= num_sessions && track_no == 0) {
 1415          if(ret <= 0)
 1416            volume_id[0]= 0;
 1417          sprintf(respt, "Incmp session: %3d , %9d , %9ds , %s\n",
 1418                  session_no+1, lba, image_blocks, volume_id);
 1419        } else if(ret>0 && track_no==0) {
 1420          sprintf(respt, "ISO session  : %3d , %9d , %9ds , %s\n",
 1421                  session_no+1, lba, image_blocks , volume_id);
 1422        } else if(ret>0) {
 1423          sprintf(respt, "ISO track    : %3d , %9d , %9ds , %s\n",
 1424                  track_count, lba, image_blocks , volume_id);
 1425        } else if(track_no==0) {
 1426          typetext= "Other session";
 1427          if(flag & 4)
 1428            typetext= "Session      ";
 1429          sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
 1430                  typetext, session_no+1, lba, track_size);
 1431        } else {
 1432          typetext= "Other track  ";
 1433          if(flag & 4)
 1434            typetext= "Track        ";
 1435          sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
 1436                  typetext, track_count, lba, track_size);
 1437        } 
 1438        if(!(flag&1))
 1439          Xorriso_toc_line(xorriso, flag & 8);
 1440        if(is_data)
 1441          num_session_data+= track_size;
 1442        else
 1443          num_session_other+= track_size;
 1444        if(track_no == 0)
 1445          first_track_start= lba;
 1446      }
 1447      isoburn_toc_session_get_leadout_entry(sessions[session_no], &toc_entry);
 1448      if (toc_entry.extensions_valid & 1) {
 1449        lba= toc_entry.start_lba;
 1450      } else {
 1451        lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe);
 1452      }
 1453      session_size= lba - first_track_start;
 1454      if(num_session_data > 0 && num_session_other > 0) {
 1455        num_data+= num_session_data;
 1456        other_data+= num_session_other;
 1457      } else if(is_data) {
 1458        num_data+= session_size;
 1459      } else {
 1460        other_data+= session_size;
 1461      }
 1462    }
 1463  }
 1464  if(xorriso->request_to_abort)
 1465    {ret= 1; goto ex;}
 1466 
 1467  Sfile_scale(((double) num_data) * 2048.0, mem_text,5,1e4,1);
 1468  sessions_seen= num_sessions + open_sessions;
 1469  if(open_sessions > 0 && !have_real_open_session)
 1470    sessions_seen--;
 1471  sprintf(respt, "Media summary: %d session%s, %d data blocks, %s data",
 1472          sessions_seen, (sessions_seen == 1 ? "" : "s"), num_data, mem_text);
 1473  if(num_data_from_format)
 1474    num_free= 0;
 1475  else
 1476    num_free= isoburn_disc_available_space(drive, NULL); 
 1477  Sfile_scale((double) num_free, mem_text,5,1e4,1);
 1478  sprintf(respt+strlen(respt), ", %s free", mem_text);
 1479 
 1480  sprintf(respt+strlen(respt), "\n");
 1481  Xorriso_toc_line(xorriso, flag & 8);
 1482 
 1483  if(other_data > 0) {
 1484    sprintf(respt, "Non-data blks: %d\n", other_data);
 1485    Xorriso_toc_line(xorriso, flag & 8);
 1486  }
 1487 
 1488  if (s==BURN_DISC_APPENDABLE && nwa!=0) {
 1489    ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
 1490    if(ret>0) {
 1491      sprintf(respt, "Media nwa    : %ds\n", nwa);
 1492      if(!(flag&1))
 1493        Xorriso_toc_line(xorriso, flag & 8);
 1494    }
 1495  }
 1496  if(profile_no == 0x41 && sessions_seen >= 300) { 
 1497    sprintf(xorriso->info_text,
 1498            "Sequential BD-R medium now contains %d sessions. It is likely to soon fail writing.",
 1499            sessions_seen);
 1500    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 1501  }
 1502 
 1503  if(have_real_open_session) {
 1504    sprintf(xorriso->info_text, "Incomplete session encountered !");
 1505    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 1506  }
 1507 
 1508  ret= 1;
 1509 ex:;
 1510  Xorriso_process_msg_queues(xorriso,0);
 1511  if (disc!=NULL)
 1512    isoburn_toc_disc_free(disc);
 1513  return(ret);
 1514 }
 1515 
 1516 
 1517 /* @param flag bit0= try to find 'meaningful' links for enumerated devices
 1518 */
 1519 int Xorriso_show_devices(struct XorrisO *xorriso, int flag)
 1520 {
 1521  char *adr= NULL, *link_adr= NULL, *adrpt;
 1522  int i, j, max_dev_len= 1, pad, ret;
 1523  struct burn_drive_info *drive_list= NULL;
 1524  unsigned int drive_count;
 1525  char *respt, perms[8];
 1526  struct stat stbuf;
 1527 
 1528  Xorriso_alloc_meM(adr, char, BURN_DRIVE_ADR_LEN);
 1529  Xorriso_alloc_meM(link_adr, char, BURN_DRIVE_ADR_LEN);
 1530 
 1531  sprintf(xorriso->info_text, "Beginning to scan for devices ...\n");
 1532  Xorriso_info(xorriso,0);
 1533 
 1534  burn_drive_clear_whitelist(); 
 1535  while(!burn_drive_scan(&drive_list, &drive_count)) {
 1536    Xorriso_process_msg_queues(xorriso,0);
 1537    usleep(100000);
 1538  }
 1539  Xorriso_process_msg_queues(xorriso,0);
 1540  if(drive_count == 0) {
 1541 
 1542    /* >>> was a drive_list created at all ? */
 1543    /* >>> must it be freed ? */
 1544 
 1545    sprintf(xorriso->info_text, "No drives found");
 1546    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 1547    {ret= 0; goto ex;}
 1548  }
 1549  sprintf(xorriso->info_text, "Full drive scan done\n");
 1550  Xorriso_info(xorriso,0);
 1551 
 1552  sprintf(xorriso->info_text, "-----------------------------------------------------------------------------\n");
 1553  Xorriso_info(xorriso,0);
 1554  respt= xorriso->result_line;
 1555  for(i= 0; i < (int) drive_count && !(xorriso->request_to_abort); i++) {
 1556    if(burn_drive_get_adr(&(drive_list[i]), adr)<=0)
 1557      strcpy(adr, "-get_adr_failed-");
 1558    Xorriso_process_msg_queues(xorriso,0);
 1559    adrpt= adr;
 1560    if(flag & 1) {
 1561      ret= burn_lookup_device_link(adr, link_adr, "/dev", NULL, 0, 0);
 1562      if(ret < 0)
 1563        goto ex;
 1564      if(ret == 1)
 1565        adrpt= link_adr;
 1566    }
 1567    if((int) strlen(adrpt) > max_dev_len)
 1568      max_dev_len= strlen(adrpt);
 1569  }
 1570  for(i= 0; i < (int) drive_count && !(xorriso->request_to_abort); i++) {
 1571    if(burn_drive_get_adr(&(drive_list[i]), adr)<=0)
 1572      strcpy(adr, "-get_adr_failed-");
 1573    Xorriso_process_msg_queues(xorriso,0);
 1574    if(stat(adr,&stbuf)==-1) {
 1575      sprintf(perms,"errno=%d",errno);
 1576    } else { 
 1577      strcpy(perms,"------");
 1578      if(stbuf.st_mode&S_IRUSR) perms[0]= 'r';
 1579      if(stbuf.st_mode&S_IWUSR) perms[1]= 'w';
 1580      if(stbuf.st_mode&S_IRGRP) perms[2]= 'r';
 1581      if(stbuf.st_mode&S_IWGRP) perms[3]= 'w';
 1582      if(stbuf.st_mode&S_IROTH) perms[4]= 'r';
 1583      if(stbuf.st_mode&S_IWOTH) perms[5]= 'w';
 1584    }
 1585    adrpt= adr;
 1586    if(flag & 1) {
 1587      ret= burn_lookup_device_link(adr, link_adr, "/dev", NULL, 0, 0);
 1588      if(ret < 0)
 1589        goto ex;
 1590      if(ret == 1)
 1591        adrpt= link_adr;
 1592    }
 1593    sprintf(respt, "%d  -dev '%s' ", i, adrpt);
 1594    pad= max_dev_len-strlen(adrpt);
 1595    if(pad>0)
 1596      for(j= 0; j<pad; j++)
 1597        strcat(respt, " ");
 1598    sprintf(respt+strlen(respt), "%s :  '%-8.8s' '%s' \n",
 1599            perms, drive_list[i].vendor, drive_list[i].product);
 1600    Xorriso_result(xorriso,0);
 1601  }
 1602  sprintf(xorriso->info_text, "-----------------------------------------------------------------------------\n");
 1603  Xorriso_info(xorriso,0);
 1604 
 1605  burn_drive_info_free(drive_list);
 1606  ret= 1;
 1607 ex:;
 1608  Xorriso_process_msg_queues(xorriso,0);
 1609  Xorriso_free_meM(adr);
 1610  Xorriso_free_meM(link_adr);
 1611  return(ret);
 1612 }
 1613 
 1614 
 1615 int Xorriso_tell_media_space(struct XorrisO *xorriso,
 1616                              int *media_space, int *free_space, int flag)
 1617 {
 1618  int ret;
 1619  struct burn_drive_info *dinfo;
 1620  struct burn_drive *drive;
 1621  struct burn_write_opts *burn_options;
 1622 
 1623  (*free_space)= (*media_space)= 0;
 1624 
 1625  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 1626                                 "on attempt to -tell_media_space", 2);
 1627  if(ret<=0)
 1628    return(0);
 1629 
 1630  ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
 1631  if(ret<=0)
 1632    return(-1);
 1633  (*free_space)= (*media_space)=
 1634               isoburn_disc_available_space(drive, burn_options) / (off_t) 2048;
 1635  burn_write_opts_free(burn_options);
 1636 
 1637  if(Xorriso_change_is_pending(xorriso, 0)) {
 1638    ret= Xorriso_write_session(xorriso, 1);
 1639    if(ret>0) {
 1640      (*free_space)-= ret;
 1641    } else {
 1642      Xorriso_process_msg_queues(xorriso,0);
 1643      return(0);
 1644    }
 1645  }
 1646  Xorriso_process_msg_queues(xorriso,0);
 1647  return(1);
 1648 }
 1649 
 1650 
 1651 /* @return <=0 error, 1 success
 1652 */
 1653 int Xorriso_list_formats(struct XorrisO *xorriso, int flag)
 1654 {
 1655  int ret, i, status, num_formats, profile_no, type, alloc_blocks, free_blocks;
 1656  off_t size;
 1657  unsigned dummy;
 1658  char status_text[80], profile_name[90], *respt;
 1659  struct burn_drive_info *dinfo;
 1660  struct burn_drive *drive;
 1661 
 1662  respt= xorriso->result_line;
 1663 
 1664  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 1665                          "on attempt to obtain format descriptor list", 1 | 2);
 1666  if(ret<=0)
 1667    return(0);
 1668  if(ret == 2)
 1669    goto ex;
 1670  ret = burn_disc_get_formats(drive, &status, &size, &dummy,
 1671                              &num_formats);
 1672  if(ret<=0) {
 1673    sprintf(xorriso->info_text, "Cannot obtain format list info");
 1674    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 1675    ret= 0; goto ex;
 1676  }
 1677  ret= Xorriso_toc(xorriso, 3);
 1678  if(ret<=0)
 1679    goto ex;
 1680  ret= burn_disc_get_profile(drive, &profile_no, profile_name);
 1681  if(ret<=0)
 1682    goto ex;
 1683 
 1684  if(status == BURN_FORMAT_IS_UNFORMATTED)
 1685    sprintf(status_text, "unformatted, up to %.1f MiB",
 1686                         ((double) size) / 1024.0 / 1024.0);
 1687  else if(status == BURN_FORMAT_IS_FORMATTED) {
 1688    if(profile_no==0x12 || profile_no==0x13 || profile_no==0x1a ||
 1689       profile_no==0x43)
 1690      sprintf(status_text, "formatted, with %.1f MiB",
 1691                          ((double) size) / 1024.0 / 1024.0);
 1692    else
 1693      sprintf(status_text, "written, with %.1f MiB",
 1694                          ((double) size) / 1024.0 / 1024.0);
 1695  } else if(status == BURN_FORMAT_IS_UNKNOWN) {
 1696    if (profile_no > 0)
 1697      sprintf(status_text, "intermediate or unknown");
 1698    else
 1699      sprintf(status_text, "no media or unknown media");
 1700  } else
 1701    sprintf(status_text, "illegal status according to MMC-5");
 1702  sprintf(respt, "Format status: %s\n", status_text);
 1703  Xorriso_result(xorriso,0);
 1704  ret= burn_disc_get_bd_spare_info(drive, &alloc_blocks, &free_blocks, 0);
 1705  if(ret == 1) {
 1706    sprintf(respt, "BD Spare Area: %d blocks consumed, %d blocks available\n",
 1707            alloc_blocks - free_blocks, free_blocks);
 1708    Xorriso_result(xorriso,0);
 1709  }
 1710 
 1711  for (i= 0; i < num_formats; i++) {
 1712    ret= burn_disc_get_format_descr(drive, i, &type, &size, &dummy);
 1713    if (ret <= 0)
 1714  continue;
 1715    sprintf(respt, "Format idx %-2d: %2.2Xh , %.fs , %.1f MiB\n",
 1716           i, type, ((double) size) / 2048.0, ((double) size) / 1024.0/1024.0);
 1717    Xorriso_result(xorriso,0);
 1718  }
 1719  ret= 1;
 1720 ex:;
 1721  return(ret);
 1722 }
 1723 
 1724 
 1725 /* @param flag bit0= This is write speed. Consider the existence of
 1726                      combo drives (e.g. DVD-ROM/CD-RW or BD-ROM/DVD+-RW)
 1727 */
 1728 int Xorriso_choose_speed_factor(struct XorrisO *xorriso,
 1729                                 int speed, int profile,
 1730                                 struct burn_drive *drive,
 1731                                 double *speed_factor, char **speed_unit,
 1732                                 int flag)
 1733 {
 1734  int i, no_dvd_read= 1, no_dvd_write= 1, no_bd_read= 1, no_bd_write= 1, ret;
 1735  int num_profiles, profiles[64];
 1736  char is_current[64];
 1737 
 1738  *speed_unit= "D";  
 1739  *speed_factor= 1385000.0;
 1740 
 1741  if((flag & 1) || profile == 0x00) {
 1742    ret= burn_drive_get_all_profiles(drive, &num_profiles,
 1743                                     profiles, is_current);
 1744    if(ret > 0) {
 1745      for(i= 0; i < num_profiles; i++) {
 1746        if(profiles[i] > 0x10 && profiles[i] < 0x30)
 1747          no_dvd_read= no_dvd_write= 0;
 1748        else if(profiles[i] == 0x10)
 1749          no_dvd_read= 0;
 1750        else if(profiles[i] > 0x40 && profiles[i] <= 0x43)
 1751          no_bd_read= no_bd_write= 0;
 1752        else if(profiles[i] == 0x40)
 1753          no_bd_read= 0;
 1754      }
 1755    }
 1756  }
 1757  if(profile == 0x00) { /* No medium loaded, guess from profile list */
 1758    if(flag & 1) {
 1759      if(no_bd_write && no_dvd_write) 
 1760        *speed_unit= "C";
 1761      else if(!no_bd_write)
 1762        *speed_unit= "B";
 1763    } else {
 1764      if(no_bd_read && no_dvd_read)
 1765        *speed_unit= "C";
 1766      else if(!no_bd_read)
 1767        *speed_unit= "B";
 1768    }
 1769  } else if((profile > 0x00 && profile <= 0x0a) ||
 1770            (((no_dvd_write && no_bd_write) && (flag & 1)))) {
 1771    *speed_unit= "C";
 1772  } else if((profile >= 0x40 && profile <= 0x43) &&
 1773            !(no_bd_write && (flag & 1))) {
 1774    *speed_unit= "B";
 1775  }
 1776  if((*speed_unit)[0] == 'C')
 1777    *speed_factor= 75.0 * 2352.0;
 1778  else if((*speed_unit)[0] == 'B')
 1779    *speed_factor= 4495625.0;
 1780  return(1);
 1781 }
 1782 
 1783 
 1784 /* For sorting the int *speeds array
 1785 */
 1786 int Xorriso__reverse_int_cmp(const void *a, const void *b)
 1787 {
 1788  int diff;
 1789 
 1790  diff= *((int *) a) - *((int *) b);
 1791  if(diff < 0)
 1792    return(1);
 1793  else if(diff > 0)
 1794    return(-1);
 1795  return(0);
 1796 }
 1797 
 1798 
 1799 /* @flag bit0= do not issue TOC
 1800          bit1= Report about outdev (else indev)
 1801          bit2= Report about write speed (else read speed)
 1802    @return <=0 error, 1 success
 1803 */
 1804 int Xorriso_list_speeds_sub(struct XorrisO *xorriso, int flag)
 1805 {
 1806  int ret, high= -1, low= 0x7fffffff, is_cd= 0, i, speed, profile= 0;
 1807  int inout_flag, prev_speed= -1, speed_count= 0;
 1808  int *speeds= NULL;
 1809  char *respt, *speed_unit= "D";
 1810  double speed_factor= 1385000.0, cd_factor= 75.0 * 2352;
 1811  struct burn_drive_info *dinfo;
 1812  struct burn_drive *drive;
 1813  struct burn_speed_descriptor *speed_list= NULL, *item, *other;
 1814 
 1815  respt= xorriso->result_line;
 1816 
 1817  inout_flag= (flag & 2);
 1818  if(inout_flag && xorriso->out_drive_handle == NULL)
 1819    inout_flag= 0;
 1820  else if(xorriso->in_drive_handle == NULL)
 1821    inout_flag= 2;
 1822  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 1823                                 "on attempt to obtain speed descriptor list",
 1824                                 1 | inout_flag);
 1825  if(ret<=0)
 1826    return(0);
 1827  if(ret == 2)
 1828    goto ex;
 1829  ret= burn_drive_get_speedlist(drive, &speed_list);
 1830  if(ret < 0) {
 1831    sprintf(xorriso->info_text, "Cannot obtain speed list info");
 1832    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 1833    ret= 0; goto ex;
 1834  }
 1835  if(!(flag & 1)) {
 1836    ret= Xorriso_toc(xorriso, 1 | inout_flag);
 1837    if(ret<=0) {
 1838      sprintf(xorriso->info_text,
 1839              "Cannot obtain overview of drive and media content");
 1840      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 1841      ret= 0; goto ex;
 1842    }
 1843  }
 1844 
 1845  speed_count= 0;
 1846  for(item= speed_list; item != NULL; item= item->next)
 1847    speed_count++;
 1848  if(speed_count > 0)
 1849    Xorriso_alloc_meM(speeds, int, speed_count);
 1850 
 1851  speed_count= 0;
 1852  for(item= speed_list; item != NULL; item= item->next) {
 1853 
 1854    sprintf(xorriso->info_text,
 1855            "read_speed= %5dk , write_speed= %5dk , source= %d",
 1856            item->read_speed, item->write_speed, item->source);
 1857    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
 1858 
 1859    if(item->source == 1) {
 1860      /* CD mode page 2Ah : report only if not same speed by GET PERFORMANCE */
 1861      if(!(flag & 4))
 1862  continue; /* 2Ah only tells write speed */
 1863      for(other= speed_list; other != NULL; other= other->next)
 1864        if(other->source == 2 && item->write_speed == other->write_speed)
 1865      break;
 1866      if(other != NULL)
 1867  continue;
 1868    }
 1869    if(flag & 4) {
 1870      if(item->write_speed <= 0)
 1871  continue;
 1872      speed= item->write_speed;
 1873    } else {
 1874      if(item->read_speed <= 0)
 1875  continue;
 1876      speed= item->read_speed;
 1877    }
 1878    speeds[speed_count]= speed;
 1879    if(item->profile_loaded > 0)
 1880      profile= item->profile_loaded;
 1881    speed_count++;
 1882  }
 1883 
 1884  if(speed_count > 0)
 1885    qsort(speeds, (size_t) speed_count, sizeof(int), Xorriso__reverse_int_cmp);
 1886 
 1887  if(profile >= 0x08 && profile <= 0x0a)
 1888    is_cd= profile;
 1889  for(i= 0; i < speed_count; i++) {
 1890 
 1891    speed= speeds[i];
 1892    if(speed == prev_speed)
 1893  continue;
 1894    prev_speed= speed;
 1895    if(flag & 4)
 1896      sprintf(respt, "Write speed  : ");
 1897    else
 1898      sprintf(respt, "Read speed   : ");
 1899   
 1900    Xorriso_choose_speed_factor(xorriso, speed, profile, drive,
 1901                                &speed_factor, &speed_unit, !!(flag & 4));
 1902    sprintf(respt + strlen(respt), " %5dk , %4.1fx%s\n",
 1903            speed, ((double) speed) * 1000.0 / speed_factor, speed_unit);
 1904    Xorriso_result(xorriso,0);
 1905    if(speed > high)
 1906      high= speed;
 1907    if(speed < low)
 1908      low= speed;
 1909  }
 1910 
 1911  /* Maybe there is ATIP info (about write speed only) */
 1912  if(is_cd && (flag & 4)) {
 1913    ret= burn_disc_read_atip(drive);
 1914    if(ret < 0)
 1915      goto ex;
 1916    if(ret > 0) {
 1917      for(i= 0; i < 2; i++) {
 1918        if(i == 0)
 1919          ret= burn_drive_get_min_write_speed(drive);
 1920        else
 1921          ret= burn_drive_get_write_speed(drive);
 1922        if(ret > 0) {
 1923          if(ret < low || (i == 0 && ret != low)) {
 1924            sprintf(respt, "Write speed l: ");
 1925            sprintf(respt + strlen(respt), " %5dk , %4.1fx%s\n",
 1926                    ret, ((double) ret) * 1000.0 / cd_factor, "C");
 1927            Xorriso_result(xorriso,0);
 1928            low= ret;
 1929          }
 1930          if(ret > high || (i == 1 && ret != high)) {
 1931            sprintf(respt, "Write speed h: ");
 1932            sprintf(respt + strlen(respt), " %5dk , %4.1fx%s\n",
 1933                    ret, ((double) ret) * 1000.0 / cd_factor, "C");
 1934            Xorriso_result(xorriso,0);
 1935            high= ret;
 1936          }
 1937        } 
 1938      }
 1939    }
 1940  }
 1941  if(high > -1) {
 1942    Xorriso_choose_speed_factor(xorriso, low, profile, drive,
 1943                                &speed_factor, &speed_unit, !!(flag & 4));
 1944    if(flag & 4)
 1945      sprintf(respt, "Write speed L: ");
 1946    else
 1947      sprintf(respt, "Read speed L : ");
 1948    sprintf(respt + strlen(respt), " %5dk , %4.1fx%s\n",
 1949            low, ((double) low) * 1000.0 / speed_factor, speed_unit);
 1950    Xorriso_result(xorriso,0);
 1951    Xorriso_choose_speed_factor(xorriso, low, profile, drive,
 1952                                &speed_factor, &speed_unit, !!(flag & 4));
 1953    if(flag & 4)
 1954      sprintf(respt, "Write speed H: ");
 1955    else
 1956      sprintf(respt, "Read speed H : ");
 1957    sprintf(respt + strlen(respt), " %5dk , %4.1fx%s\n",
 1958            high, ((double) high) * 1000.0 / speed_factor, speed_unit);
 1959    Xorriso_result(xorriso,0);
 1960    ret= burn_drive_get_best_speed(drive, 0, &item, 2);
 1961    if(ret > 0 && item != NULL && (flag & 4))
 1962      if(item->write_speed != high) {
 1963        sprintf(respt, "Write speed 0:  %5dk , %4.1fx%s\n",
 1964                item->write_speed,
 1965              ((double) item->write_speed) * 1000.0 / speed_factor, speed_unit);
 1966        Xorriso_result(xorriso,0);
 1967      }
 1968  } else {
 1969    sprintf(xorriso->info_text,
 1970            "Could not get any %s speed information from drive",
 1971            (flag & 4) ? "write" : "read");
 1972    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
 1973    ret= 2; goto ex;
 1974  }
 1975  ret= 1;
 1976 ex:;
 1977  if(speed_list != NULL)
 1978    burn_drive_free_speedlist(&speed_list);
 1979  Xorriso_free_meM(speeds);
 1980  return(ret);
 1981 }
 1982 
 1983 
 1984 int Xorriso_list_speeds(struct XorrisO *xorriso, int flag)
 1985 {
 1986  int ret;
 1987 
 1988  if(xorriso->out_drive_handle == NULL && xorriso->in_drive_handle == NULL) {
 1989    Xorriso_msgs_submit(xorriso, 0,
 1990                "No drive acquired on attempt to list speeds", 0, "FAILURE", 0);
 1991    return(0);
 1992  }
 1993  if(xorriso->in_drive_handle != NULL) {
 1994    ret= Xorriso_list_speeds_sub(xorriso, 0);
 1995    if(ret <= 0)
 1996      return(ret);
 1997  }
 1998  if(xorriso->out_drive_handle != NULL &&
 1999     xorriso->out_drive_handle != xorriso->in_drive_handle) {
 2000    ret= Xorriso_list_speeds_sub(xorriso, 2);
 2001    if(ret <= 0)
 2002      return(ret);
 2003  }
 2004  if(xorriso->out_drive_handle != NULL) {
 2005    ret= Xorriso_list_speeds_sub(xorriso, 1 | 2 | 4);
 2006    if(ret <= 0)
 2007      return(ret);
 2008  }
 2009  return(1);
 2010 }
 2011 
 2012 
 2013 /* @param flag bit0= cdrecord style
 2014                bit1= obtain outdrive, else indrive
 2015    @return <=0 error, 1 success
 2016 */
 2017 int Xorriso_list_profiles(struct XorrisO *xorriso, int flag)
 2018 {
 2019  int ret, i;
 2020  struct burn_drive_info *dinfo;
 2021  struct burn_drive *drive;
 2022  int num_profiles, profiles[64];
 2023  char is_current[64], profile_name[90], *respt;
 2024 
 2025  respt= xorriso->result_line;
 2026 
 2027  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2028                           "on attempt to obtain profile list", 1 | (flag & 2));
 2029  if(ret<=0)
 2030    return(0);
 2031  burn_drive_get_all_profiles(drive, &num_profiles, profiles, is_current);
 2032  for(i= 0; i < num_profiles; i++) {
 2033    ret= burn_obtain_profile_name(profiles[i], profile_name);
 2034    if(ret <= 0)
 2035      strcpy(profile_name, "unknown");
 2036    sprintf(respt, "%s 0x%4.4X (%s)%s\n",
 2037            flag & 1 ? "Profile:" : "Profile      :",
 2038            (unsigned int) profiles[i],
 2039            profile_name, is_current[i] ? " (current)" : "");
 2040    Xorriso_result(xorriso,0);
 2041  }
 2042  return(1);
 2043 }
 2044 
 2045 
 2046 /* @param flag bit0= -inq
 2047                bit1= -checkdrive
 2048 */
 2049 int Xorriso_atip(struct XorrisO *xorriso, int flag)
 2050 {
 2051  int ret, profile_number= 0, is_bdr_pow= 0;
 2052  int num_profiles= 0, profiles[64], i, can_write= 0, pf, no_medium= 0;
 2053  char is_current[64];
 2054  char *respt, profile_name[80];
 2055  double x_speed_max, x_speed_min= -1.0;
 2056  struct burn_drive_info *dinfo;
 2057  struct burn_drive *drive;
 2058  enum burn_disc_status s;
 2059  char *manuf= NULL, *media_code1= NULL, *media_code2= NULL;
 2060  char *book_type= NULL, *product_id= NULL;
 2061 
 2062  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2063                            "on attempt to print drive and media info", 2);
 2064  if(ret<=0)
 2065    return(0);
 2066  respt= xorriso->result_line;
 2067  sprintf(respt, "Device type    : ");
 2068  ret= burn_drive_get_drive_role(drive);
 2069  if(ret==0)
 2070    sprintf(respt+strlen(respt), "%s\n", "Emulated (null-drive)");
 2071  else if(ret==2)
 2072    sprintf(respt+strlen(respt), "%s\n",
 2073            "Emulated (stdio-drive, 2k random read-write)");
 2074  else if(ret==3)
 2075    sprintf(respt+strlen(respt), "%s\n",
 2076            "Emulated (stdio-drive, sequential write-only)");
 2077  else if(ret == 4)
 2078    sprintf(respt+strlen(respt), "%s\n",
 2079            "Emulated (stdio-drive, 2k random read-only)");
 2080  else if(ret == 5)
 2081    sprintf(respt+strlen(respt), "%s\n",
 2082            "Emulated (stdio-drive, 2k random write-only)");
 2083  else if(ret!=1)
 2084    sprintf(respt+strlen(respt), "%s\n","Emulated (stdio-drive)");
 2085  else
 2086    sprintf(respt+strlen(respt), "%s\n","Removable CD-ROM");
 2087  sprintf(respt+strlen(respt), "Vendor_info    : '%s'\n",dinfo->vendor);
 2088  sprintf(respt+strlen(respt), "Identifikation : '%s'\n",dinfo->product);
 2089  sprintf(respt+strlen(respt), "Revision       : '%s'\n",dinfo->revision);
 2090  Xorriso_result(xorriso,1);
 2091  if(flag&1)
 2092    return(1);
 2093 
 2094  /* Do not report "Supported modes: SAO TAO" with -ROM drives */
 2095  burn_drive_get_all_profiles(drive, &num_profiles, profiles, is_current);
 2096  if(num_profiles > 0) {
 2097    for(i= 0; i < num_profiles; i++) {
 2098      pf= profiles[i];
 2099      if(pf == 0x09 || pf == 0x0a || pf == 0x11 || pf == 0x12 || pf == 0x13 ||
 2100         pf == 0x14 || pf == 0x15 || pf == 0x1a || pf == 0x1b || pf == 0x2b ||
 2101         pf == 0x41 || pf == 0x43 || pf == 0xffff) {
 2102        can_write= 1;
 2103    break;
 2104      }
 2105    }
 2106  } else
 2107    can_write= 1;
 2108  if(can_write) {
 2109    sprintf(respt, "Driver flags   : BURNFREE\n");
 2110    sprintf(respt+strlen(respt), "Supported modes: SAO TAO\n");
 2111    Xorriso_result(xorriso,1);
 2112  } else if(flag & 2) {
 2113    sprintf(xorriso->info_text, "Not a CD/DVD/BD recorder");
 2114    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 2115  }
 2116  if(flag&2)
 2117    return(1);
 2118 
 2119  is_bdr_pow= burn_drive_get_bd_r_pow(drive);
 2120  s= burn_disc_get_status(drive);
 2121  ret= burn_disc_get_profile(drive,&profile_number,profile_name);
 2122  if(ret<=0) {
 2123    profile_number= 0;
 2124    strcpy(profile_name, "-unidentified-");
 2125  }
 2126  if(s != BURN_DISC_UNSUITABLE) {
 2127    ret= burn_disc_read_atip(drive);
 2128    if(ret>0) {
 2129      ret= burn_drive_get_min_write_speed(drive);
 2130      x_speed_min= ((double) ret)/176.4;
 2131    }
 2132  }
 2133  if(s==BURN_DISC_EMPTY) {
 2134    sprintf(respt, "Current: none\n");
 2135    Xorriso_result(xorriso,1);
 2136    sprintf(xorriso->info_text, "No recognizable medium found in drive");
 2137    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 2138    no_medium= 1;
 2139  } else 
 2140    sprintf(respt, "Current: %s%s\n",profile_name,
 2141            is_bdr_pow ? ", Pseudo Overwrite formatted" : "");
 2142  Xorriso_result(xorriso,1);
 2143  Xorriso_list_profiles(xorriso, 1 | 2);
 2144  if(no_medium)
 2145    return(1);
 2146  if(strstr(profile_name,"BD")==profile_name) {
 2147    printf("Mounted Media: %2.2Xh, %s\n", profile_number, profile_name);
 2148  } else if(strstr(profile_name,"DVD")==profile_name) {
 2149    sprintf(respt, "book type:     %s (emulated booktype)\n", profile_name);
 2150    Xorriso_result(xorriso,1);
 2151    if(profile_number == 0x13) {
 2152      sprintf(respt, "xorriso: message for sdvdbackup: \"(growisofs mode Restricted Overwrite)\"\n");
 2153      Xorriso_result(xorriso,1);
 2154    }
 2155  } else {
 2156    sprintf(respt, "ATIP info from disk:\n");
 2157    Xorriso_result(xorriso,1);
 2158    if(burn_disc_erasable(drive))
 2159      sprintf(respt, "  Is erasable\n");
 2160    else
 2161      sprintf(respt, "  Is not erasable\n");
 2162    Xorriso_result(xorriso,1);
 2163    { int start_lba,end_lba,min,sec,fr;
 2164      ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0);
 2165      if(ret>0) {
 2166        burn_lba_to_msf(start_lba,&min,&sec,&fr);
 2167        sprintf(respt, "  ATIP start of lead in:  %d (%-2.2d:%-2.2d/%-2.2d)\n",
 2168               start_lba,min,sec,fr);
 2169        Xorriso_result(xorriso,1);
 2170        burn_lba_to_msf(end_lba,&min,&sec,&fr);
 2171        sprintf(respt, "  ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
 2172               end_lba,min,sec,fr);
 2173        Xorriso_result(xorriso,1);
 2174      }
 2175    }
 2176    ret= burn_drive_get_write_speed(drive);
 2177    x_speed_max= ((double) ret)/176.4;
 2178    if(x_speed_min<0)
 2179      x_speed_min= x_speed_max;
 2180    sprintf(respt,
 2181           "  1T speed low:  %.f 1T speed high: %.f\n",x_speed_min,x_speed_max);
 2182    Xorriso_result(xorriso,1);
 2183  }
 2184 
 2185  ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2,
 2186                                 &book_type, 0);
 2187  if(ret > 0 && media_code1 != NULL && media_code2 != NULL)
 2188    manuf= burn_guess_manufacturer(profile_number, media_code1, media_code2, 0);
 2189  if(product_id != NULL) {
 2190    sprintf(respt, "Product Id:    %s\n", product_id);
 2191    Xorriso_result(xorriso,1);
 2192  }
 2193  if(manuf != NULL) {
 2194    sprintf(respt, "Producer:      %s\n", manuf);
 2195    Xorriso_result(xorriso, 1);
 2196  }
 2197  if(profile_number == 0x09 || profile_number == 0x0a) {
 2198    sprintf(respt, "Manufacturer: %s\n", manuf);
 2199    Xorriso_result(xorriso, 1);
 2200  } else if(product_id != NULL && media_code1 != NULL && media_code2 != NULL){
 2201    free(product_id);
 2202    free(media_code1);
 2203    free(media_code2);
 2204    if(book_type != NULL)
 2205      free(book_type);
 2206    product_id= media_code1= media_code2= book_type= NULL;
 2207    ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2,
 2208                                &book_type, 1);
 2209    if(ret > 0) {
 2210      sprintf(respt, "Manufacturer:  '%s'\n", media_code1);
 2211      Xorriso_result(xorriso, 1);
 2212      if(media_code2[0]) {
 2213        sprintf(respt, "Media type:    '%s'\n", media_code2);
 2214        Xorriso_result(xorriso, 1);
 2215      }
 2216    }
 2217  }
 2218  if(manuf != NULL)
 2219    free(manuf);
 2220  if(media_code1 != NULL)
 2221    free(media_code1);
 2222  if(media_code2 != NULL)
 2223    free(media_code2);
 2224  if(book_type != NULL)
 2225    free(book_type);
 2226  if(product_id != NULL)
 2227    free(product_id);
 2228  return(1);
 2229 }
 2230 
 2231 
 2232 /* @param flag bit1= outdev rather than indev
 2233    @return <0 error, 0 = no profile to see , 1= ok , 2= ok, is CD profile
 2234                                                      3= ok, is BD profile
 2235 */
 2236 int Xorriso_get_profile(struct XorrisO *xorriso, int *profile_number, 
 2237                         char profile_name[80], int flag)
 2238 {
 2239  int ret;
 2240  struct burn_drive_info *dinfo;
 2241  struct burn_drive *drive;
 2242 
 2243  *profile_number= 0;
 2244  profile_name[0]= 0;
 2245  if(((flag&2) && xorriso->out_drive_handle==NULL) ||
 2246     ((!(flag&2)) && xorriso->in_drive_handle==NULL))
 2247    return(0);
 2248  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2249                                 "on attempt to determine media type", flag&2);
 2250  if(ret<=0)
 2251    return(0);
 2252  ret=burn_disc_get_profile(drive, profile_number, profile_name);
 2253  if(ret<=0)
 2254    return(ret);
 2255  if(*profile_number==0x08 || *profile_number==0x09 || *profile_number==0x0a)
 2256    return(2);
 2257  if(*profile_number == 0x40 || *profile_number == 0x41 ||
 2258     *profile_number == 0x42 || *profile_number == 0x43)
 2259    return(3);
 2260  return(0);
 2261 }
 2262 
 2263 
 2264 /* @param flag bit0= grow_overwriteable_iso
 2265                bit1= obtain info from outdev
 2266                bit2= no need to obtain msc2 (NWA)
 2267 */
 2268 int Xorriso_msinfo(struct XorrisO *xorriso, int *msc1, int *msc2, int flag)
 2269 {
 2270  int ret, dummy, is_bdr_pow= 0;
 2271  struct burn_drive *drive;
 2272  struct burn_drive_info *dinfo;
 2273  enum burn_disc_status disc_state;
 2274 
 2275  *msc1= *msc2= -1;
 2276  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2277                                 "on attempt to obtain msinfo", flag&2);
 2278  if(ret<=0)
 2279    return(ret);
 2280 
 2281  is_bdr_pow=  burn_drive_get_bd_r_pow(drive);
 2282  if(is_bdr_pow) {
 2283    Xorriso_process_msg_queues(xorriso,0);
 2284    sprintf(xorriso->info_text,
 2285           "%s medium is unsuitably POW formatted BD-R. Cannot obtain -msinfo.",
 2286           (flag&2) ? "Output" : "Input");
 2287    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 2288    return(0);
 2289  }
 2290  if(flag&1)
 2291    disc_state= isoburn_disc_get_status(drive);
 2292  else
 2293    disc_state= burn_disc_get_status(drive);
 2294  if(disc_state != BURN_DISC_APPENDABLE &&
 2295     !(disc_state == BURN_DISC_FULL && (flag & 4))) {
 2296    Xorriso_process_msg_queues(xorriso,0);
 2297    if(!(flag & 4)) {
 2298      sprintf(xorriso->info_text,
 2299              "%s medium is not appendable. Cannot obtain -msinfo.",
 2300              (flag&2) ? "Output" : "Input");
 2301      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 2302    }
 2303    return(0);
 2304  }
 2305  ret= isoburn_disc_get_msc1(drive, msc1);
 2306  if(ret<=0) {
 2307    Xorriso_process_msg_queues(xorriso,0);
 2308    sprintf(xorriso->info_text, "Cannot obtain address of most recent session");
 2309    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 2310    return(0);
 2311  }
 2312  if(flag & 4)
 2313    return(1);
 2314  ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &dummy, msc2);
 2315  if(ret<0) {
 2316    Xorriso_process_msg_queues(xorriso,0);
 2317    sprintf(xorriso->info_text, "Cannot obtain next writeable address on media");
 2318    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 2319    return(0);
 2320  }
 2321  return(1);
 2322 }
 2323 
 2324 
 2325 /* @param flag bit0=input drive
 2326                bit1=output drive
 2327                bit2= wake up rather than calm down
 2328 */
 2329 int Xorriso_drive_snooze(struct XorrisO *xorriso, int flag)
 2330 {
 2331  int in_is_out_too, ret;
 2332  struct burn_drive_info *dinfo;
 2333  struct burn_drive *drive;
 2334  
 2335  in_is_out_too= (xorriso->in_drive_handle == xorriso->out_drive_handle);
 2336  if((flag & 1) && xorriso->in_drive_handle != NULL) {
 2337    Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2338                              "on attempt to calm drive", 0);
 2339    burn_drive_snooze(drive, !!(flag & 4));
 2340    if(in_is_out_too)
 2341      {ret= 1; goto ex;}
 2342  }
 2343  if((flag&2) && xorriso->out_drive_handle!=NULL) {
 2344    Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2345                              "on attempt to calm drive", 2);
 2346    burn_drive_snooze(drive, !!(flag & 4));
 2347  }
 2348  ret= 1;
 2349 ex:;
 2350  Xorriso_process_msg_queues(xorriso,0);
 2351  return(ret);
 2352 }
 2353 
 2354 
 2355 /* @param flag bit0= enable SCSI command logging to stderr */
 2356 int Xorriso_scsi_log(struct XorrisO *xorriso, int flag)
 2357 {
 2358  if(flag == 0)
 2359    burn_set_scsi_logging(0);
 2360  else
 2361    burn_set_scsi_logging(2|4);
 2362  return(1);
 2363 }
 2364 
 2365 
 2366 int Xorriso_check_md5_range(struct XorrisO *xorriso, off_t start_lba,
 2367                             off_t end_lba, char md5[16], int flag)
 2368 {
 2369  int ret, us_corr = 0;
 2370  struct burn_drive_info *dinfo= NULL;
 2371  struct burn_drive *drive= NULL;
 2372  off_t pos, data_count, to_read, slowdown_count= 0;
 2373  char *data= NULL, data_md5[16];
 2374  void *ctx = NULL;
 2375  struct timeval prev_time;
 2376 
 2377  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2378                                 "on attempt to check session MD5 checksum", 0);
 2379  if(ret <= 0)
 2380    goto ex;
 2381 
 2382  Xorriso_alloc_meM(data, char, 64 * 1024);
 2383 
 2384  ret= iso_md5_start(&ctx);
 2385  if(ret <= 0) {
 2386    Xorriso_no_malloc_memory(xorriso, NULL, 0);
 2387    goto ex;
 2388  }
 2389  if(xorriso->read_speed_force > 0) /* initialize forced speed limit */
 2390    burn_nominal_slowdown(xorriso->read_speed_force, xorriso->read_speed_corr,
 2391                          &prev_time, &us_corr, (off_t) 0, 1);
 2392  Xorriso_set_speed(xorriso, drive, xorriso->read_speed, 0, 1);
 2393  Xorriso_process_msg_queues(xorriso,0);
 2394  for(pos= start_lba; pos < end_lba; pos+= 32) {
 2395    to_read= 32;
 2396    if(pos + to_read > end_lba)
 2397      to_read= end_lba - pos; 
 2398    ret= burn_read_data(drive, pos * (off_t) 2048, data,
 2399                        to_read * (off_t) 2048, &data_count, 0);
 2400    if(ret <= 0)
 2401      goto ex;
 2402    iso_md5_compute(ctx, data, (int) data_count);
 2403    if(xorriso->read_speed_force > 0 && pos + to_read <= end_lba) {
 2404      slowdown_count+= data_count;
 2405      if(slowdown_count >= 128 * 1024) {
 2406        burn_nominal_slowdown(xorriso->read_speed_force,
 2407                              xorriso->read_speed_corr,
 2408                              &prev_time, &us_corr, slowdown_count, 0);
 2409        slowdown_count= 0;
 2410      }
 2411    }
 2412    xorriso->pacifier_count+= data_count; 
 2413    xorriso->pacifier_byte_count+= data_count;
 2414    Xorriso_pacifier_callback(xorriso, "content bytes read",
 2415                              xorriso->pacifier_count, 0, "", 8);
 2416  }
 2417  iso_md5_end(&ctx, data_md5);
 2418  ret= 1;
 2419  if(! iso_md5_match(md5, data_md5))
 2420    ret= 0;
 2421 ex:;
 2422  Xorriso_process_msg_queues(xorriso,0);
 2423  if(ctx != NULL)
 2424    iso_md5_end(&ctx, data_md5);
 2425  Xorriso_free_meM(data);
 2426  return(ret);
 2427 }
 2428 
 2429 
 2430 int Xorriso_check_session_md5(struct XorrisO *xorriso, char *severity,
 2431                               int flag)
 2432 {
 2433  int ret, i;
 2434  IsoImage *image;
 2435  uint32_t start_lba, end_lba;
 2436  char md5[16], md5_text[33];
 2437 
 2438  ret= Xorriso_get_volume(xorriso, &image, 0);
 2439  if(ret<=0)
 2440    return(ret);
 2441  ret= iso_image_get_session_md5(image, &start_lba, &end_lba, md5, 0);
 2442  Xorriso_process_msg_queues(xorriso,0);
 2443  if(ret < 0)
 2444    return(ret);
 2445  if(ret == 0) {
 2446    sprintf(xorriso->info_text,
 2447            "No session MD5 is recorded with the loaded session");
 2448    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 2449    return(0);
 2450  }
 2451 
 2452  sprintf(xorriso->info_text, "Checking loaded session by its recorded MD5.\n"); 
 2453  Xorriso_info(xorriso, 0);
 2454  for(i= 0; i < 16; i++)
 2455    sprintf(md5_text + 2 * i, "%2.2x", ((unsigned char *) md5)[i]);
 2456  sprintf(xorriso->result_line,
 2457          "Session MD5 %s , LBA %.f , %.f blocks\n",
 2458          md5_text, (double) start_lba, (double) end_lba - start_lba);
 2459  Xorriso_result(xorriso,0);
 2460  ret= Xorriso_check_md5_range(xorriso, (off_t) start_lba, (off_t) end_lba,
 2461                               md5, 0);
 2462  return(ret);
 2463 }
 2464 
 2465  
 2466 int Xorriso_check_for_abort(struct XorrisO *xorriso,
 2467                             char *abort_file_path,
 2468                             double post_read_time,
 2469                             double *last_abort_file_time, int flag)
 2470 {
 2471  struct stat stbuf;
 2472 
 2473  if(abort_file_path[0] == 0)
 2474    return(0);
 2475  if(post_read_time - *last_abort_file_time >= 0.1) {
 2476    if(stat(abort_file_path, &stbuf) != -1) {
 2477      if(stbuf.st_mtime >= xorriso->start_time) {
 2478        sprintf(xorriso->info_text,
 2479                "-check_media: Found fresh abort_file=%s", abort_file_path);
 2480        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
 2481        return(1);
 2482      }
 2483    }
 2484    *last_abort_file_time= post_read_time;
 2485  }
 2486  return(0);
 2487 }
 2488 
 2489 
 2490 struct xorriso_md5_state {
 2491 
 2492   /* Resources */
 2493   struct XorrisO *xorriso;
 2494   void *ctx;
 2495   struct SpotlisT *spotlist;
 2496   pthread_mutex_t spot_mutex;
 2497 
 2498   /* Checksum tag cursor */
 2499   uint32_t md5_start;
 2500   uint32_t next_tag;
 2501   int chain_broken;
 2502   int in_track_gap;
 2503   int was_sb_tag;
 2504   int md5_spot_value;
 2505   uint32_t md5_spot_lba;
 2506 
 2507   /* Asynchronous operation */
 2508 
 2509   int slave_state;   /* Operated by slave 
 2510                         0= not yet started
 2511                         1= slave is started
 2512                         2= slave has reached its end
 2513                         3= slave failed to start
 2514                       */
 2515   int chunk_size;
 2516   int num_chunks;
 2517   char **chunk;
 2518   int *chunk_state;  /*  0= content invalid (set by boss at creation time),
 2519                          1= content readable (set by boss),
 2520                          2= content was read (set by MD5 slave),
 2521                          3= end-of-processing (set by boss when done)
 2522                       */
 2523   int *chunk_fill;    /* Actual number of valid bytes in chunk */
 2524   uint32_t *chunk_lba;
 2525   int chunk_w_idx;    /* Write index. Operated by boss */
 2526   int chunk_r_idx;    /* Read index. Operated by MD5 slave */
 2527 
 2528   off_t w_sleeps;
 2529   off_t r_sleeps;
 2530 
 2531 };
 2532 
 2533 
 2534 int Xorriso__add_spot(struct xorriso_md5_state *state,
 2535                       int start_lba, int blocks, int quality, int flag)
 2536 {
 2537  int ret, uret;
 2538 
 2539  if(state->chunk != NULL) {
 2540    ret= pthread_mutex_lock(&(state->spot_mutex));
 2541    if(ret != 0)
 2542      return(0);
 2543  }
 2544  ret= Spotlist_add_item(state->spotlist, start_lba, blocks, quality, 0);
 2545  if(state->chunk != NULL) {
 2546    uret= pthread_mutex_unlock(&(state->spot_mutex));
 2547    if(uret != 0 && ret > 0)
 2548      ret= 0;
 2549  }
 2550  return(ret);
 2551 }
 2552 
 2553 
 2554 int Xorriso_chunk_md5(struct XorrisO *xorriso, char *data, int to_read,
 2555                   uint32_t from_lba, struct xorriso_md5_state *state, int flag)
 2556 {
 2557  int j, ret= 0, valid, tag_type, decode_ret= 0;
 2558  uint32_t lba, pos, range_start, range_size;
 2559  char md5[16], tag_md5[16], *tag_type_name= "", *comparison, *sev_text;
 2560  void *cloned_ctx= NULL;
 2561 
 2562  for(j= 0; j < to_read; j++) {
 2563    lba=  j + from_lba;
 2564    if(lba < state->md5_start)
 2565  continue;
 2566    ret= decode_ret= 0;
 2567    if(lba > state->md5_start + 16 &&
 2568       (state->next_tag == 0 || state->chain_broken || lba == state->next_tag)){
 2569      ret= iso_util_decode_md5_tag(data + j * 2048, &tag_type,
 2570                                   &pos, &range_start, &range_size,
 2571                                   &(state->next_tag), tag_md5,
 2572                                   !!state->chain_broken);
 2573      decode_ret= ret;
 2574    }
 2575    valid= (ret == 1 || ret == (int) ISO_MD5_AREA_CORRUPTED) && pos == lba;
 2576    if(valid && tag_type == 2 && (lba < state->md5_start + 32 ||
 2577       state->in_track_gap)){
 2578      tag_type_name= "superblock";
 2579      state->was_sb_tag= 1;
 2580      if(state->in_track_gap && range_start != state->md5_start &&
 2581         range_start < lba && lba - range_start <= (uint32_t) j) {
 2582        /* Looking for next session : start computing in hindsight.
 2583           Session start and superblock tag are supposed to be in the
 2584           same 64 kB chunk.
 2585        */
 2586        iso_md5_end(&(state->ctx), md5);
 2587        ret= iso_md5_start(&(state->ctx));
 2588        if(ret < 0) {
 2589          Xorriso_no_malloc_memory(xorriso, NULL, 0);
 2590          ret= -1; goto ex;
 2591        }
 2592        iso_md5_compute(&(state->ctx), data + (j - (lba - range_start)) * 2048,
 2593                        (lba - range_start) * 2048);
 2594        state->md5_start= range_start;
 2595        state->in_track_gap= 0;
 2596      }
 2597    } else if(valid && tag_type == 4 && lba < 32) {
 2598      tag_type_name= "relocated 64kB superblock";
 2599    }else if(valid && tag_type == 3 && state->was_sb_tag) {
 2600      tag_type_name= "tree";
 2601    }else if(valid && tag_type == 1) {
 2602 
 2603      /* >>> ??? allow this without superblock and tree tag ? */
 2604 
 2605      tag_type_name= "session";
 2606    } else {
 2607      tag_type_name= "";
 2608    }
 2609    if (tag_type_name[0]) {
 2610      if(range_start != state->md5_start) {
 2611        sprintf(xorriso->info_text,
 2612           "Found MD5 %s tag which covers different data range", tag_type_name);
 2613        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE",0);
 2614        sprintf(xorriso->info_text, "              Expected: %u  Found: %u",
 2615                (unsigned int) state->md5_start, range_start);
 2616        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE",0);
 2617        state->chain_broken= 1;
 2618        valid= 0;
 2619      } else {
 2620        ret= iso_md5_clone(state->ctx, &cloned_ctx);
 2621        if(ret <= 0) {
 2622          Xorriso_no_malloc_memory(xorriso, NULL, 0);
 2623          ret= -1; goto ex;
 2624        }
 2625        iso_md5_end(&cloned_ctx, md5);
 2626 
 2627        if(decode_ret == (int) ISO_MD5_AREA_CORRUPTED) {
 2628          comparison= "CORRUPTED";
 2629          sev_text= "WARNING";
 2630          state->md5_spot_value= Xorriso_read_quality_md5_mismatcH;
 2631          state->chain_broken= 1;
 2632        } else if(! iso_md5_match(tag_md5, md5)) {
 2633          comparison= "NON-MATCHING";
 2634          sev_text= "WARNING";
 2635          state->md5_spot_value= Xorriso_read_quality_md5_mismatcH;
 2636          state->chain_broken= 1;
 2637        } else {
 2638          comparison= "matching";
 2639          sev_text= "UPDATE";
 2640          state->md5_spot_value= Xorriso_read_quality_md5_matcH;
 2641        }
 2642        state->md5_spot_lba= lba;
 2643        sprintf(xorriso->info_text,
 2644                "Found %s MD5 %s tag: start=%d size=%d",
 2645                comparison, tag_type_name, state->md5_start,
 2646                lba - state->md5_start);
 2647        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev_text, 0);
 2648      }
 2649      if(valid && (tag_type == 1 || (tag_type == 4 && pos == lba && lba < 32))){
 2650        if(state->md5_spot_value != Xorriso_read_quality_untesteD) {
 2651          ret= Xorriso__add_spot(state, state->md5_start,
 2652              state->md5_spot_lba - state->md5_start, state->md5_spot_value, 0);
 2653          if(ret <= 0)
 2654          goto ex;
 2655        }
 2656        state->md5_spot_value= Xorriso_read_quality_untesteD;
 2657        state->md5_start = lba + 1;
 2658        if(state->md5_start % 32)
 2659          state->md5_start= state->md5_start + (32 - (state->md5_start % 32));
 2660        state->next_tag= 0;
 2661 
 2662        iso_md5_end(&(state->ctx), md5);
 2663        ret= iso_md5_start(&(state->ctx));
 2664        if(ret < 0) {
 2665          Xorriso_no_malloc_memory(xorriso, NULL, 0);
 2666          ret= -1; goto ex;
 2667        }
 2668        if(tag_type == 1)
 2669          state->in_track_gap= 1;
 2670  continue;
 2671      }
 2672    }
 2673    iso_md5_compute(state->ctx, data + j * 2048, 2048);
 2674  }
 2675  ret= 1;
 2676 ex:;
 2677  return(ret);
 2678 }
 2679 
 2680 
 2681 static void *Xorriso__md5_slave(void *state_pt)
 2682 {
 2683  struct xorriso_md5_state *state;
 2684  int ret, c_state, c_idx;
 2685  static int u_wait= 1;
 2686 
 2687  state= state_pt;
 2688  state->slave_state= 1;
 2689 
 2690  while(1) {
 2691    c_idx= state->chunk_r_idx;
 2692    c_state= state->chunk_state[c_idx];
 2693    if(c_state == 1) {
 2694      ret= Xorriso_chunk_md5(state->xorriso, state->chunk[c_idx],
 2695                             state->chunk_fill[c_idx], state->chunk_lba[c_idx],
 2696                             state, 0);
 2697      if(ret <= 0)
 2698        goto ex;
 2699      state->chunk_state[c_idx]= 2;
 2700      state->chunk_r_idx= (c_idx + 1) % state->num_chunks;
 2701    } else if(c_state == 3) {
 2702      goto ex;
 2703    } else {
 2704 
 2705      /* >>> have a timeout ? */;
 2706 
 2707      if(u_wait > 0)
 2708        usleep(u_wait);
 2709      state->r_sleeps++;
 2710    }
 2711  }
 2712 
 2713 ex:;
 2714  state->slave_state= 2;
 2715  return NULL;
 2716 }
 2717 
 2718 
 2719 int Xorriso_start_chunk_md5(struct XorrisO *xorriso,
 2720                             struct xorriso_md5_state *state, int flag)
 2721 {
 2722  int ret, u_wait= 1000;
 2723  pthread_attr_t attr;
 2724  pthread_attr_t *attr_pt = NULL;
 2725  pthread_t thread;
 2726 
 2727  pthread_attr_init(&attr);
 2728  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 2729  attr_pt= &attr;
 2730 
 2731  ret= pthread_create(&thread, attr_pt, Xorriso__md5_slave, state);
 2732  if(ret != 0) {
 2733    sprintf(xorriso->info_text,
 2734            "-check_media: Cannot create thread for MD5 computation");
 2735    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
 2736    ret= 0; goto ex;
 2737  }
 2738 
 2739  while(state->slave_state != 1) {
 2740 
 2741    /* >>> have a timeout ? */;
 2742      /* >>> if this fails set  state->slave_state= 3 */
 2743 
 2744    usleep(u_wait);
 2745  }
 2746  ret= 1;
 2747 ex:;
 2748  return(ret);
 2749 }
 2750 
 2751 
 2752 int Xorriso__wait_chunk_md5(struct xorriso_md5_state *state,
 2753                             int u_wait, int flag)
 2754 {
 2755  if(state->chunk_state == NULL)
 2756    return(1);
 2757  while(state->chunk_state[state->chunk_w_idx] == 1) {
 2758 
 2759      /* >>> have a timeout ? */;
 2760 
 2761      usleep(u_wait);
 2762      state->w_sleeps++;
 2763   }
 2764   return(1);
 2765 }
 2766 
 2767 
 2768 int Xorriso__wait_slave_md5_end(struct xorriso_md5_state *state,
 2769                                 int u_wait, int flag)
 2770 {
 2771  while(state->slave_state == 1) {
 2772 
 2773      /* >>> have a timeout ? */;
 2774 
 2775      usleep(u_wait);
 2776   }
 2777   return(1);
 2778 }
 2779 
 2780 
 2781 int Xorriso__end_slave_md5(struct xorriso_md5_state *state,
 2782                                 int u_wait, int flag)
 2783 {
 2784  int i, ret;
 2785 
 2786  /* Tell slave thread to end */
 2787  for(i= 0; i < state->num_chunks; i++) {
 2788    ret= Xorriso__wait_chunk_md5(state, 10000, 0);
 2789    if(ret <= 0)
 2790      return(ret);
 2791    state->chunk_state[state->chunk_w_idx]= 3;
 2792    state->chunk_w_idx= (state->chunk_w_idx + 1) % state->num_chunks;
 2793  }
 2794  /* Wait for slave to end */
 2795  ret= Xorriso__wait_slave_md5_end(state, 10000, 0);
 2796  if(ret <= 0)
 2797    return(ret);
 2798  return(1);
 2799 }
 2800 
 2801  
 2802 /* @param flag bit0= this is a follow-up session (i.e. on CD: TAO)
 2803                bit1= no pacifier messages
 2804                bit2= compute stream MD5 and look out for checksum tag
 2805    @return <=0 error, 1= done, 2= aborted due to limit
 2806 */
 2807 int Xorriso_check_interval(struct XorrisO *xorriso, struct SpotlisT *spotlist,
 2808                            struct CheckmediajoB *job,
 2809                            int from_lba, int block_count, int read_chunk,
 2810                            int md5_start, int flag)
 2811 {
 2812  int i, j, ret, total_count= 0, sectors= -1, sector_size= -1, skip_reading;
 2813  int prev_quality= -1, quality= -1, retry= 0, profile_no, is_cd= 0;
 2814  int eccb_size= 16, us_corr = 0, data_skip;
 2815  int start_sec, end_sec, first_value, fret, suspect_tao_end= 0;
 2816  char profile_name[80];
 2817  int start_lba= 0;
 2818  struct burn_drive *drive;
 2819  struct burn_drive_info *dinfo;
 2820  char *data= NULL, *data_pt;
 2821  off_t data_count, to_read, read_count= 0, write_amount, skipped_to_read;
 2822  off_t slowdown_count= 0, seek_adr;
 2823  struct timeval prev_time;
 2824  double pre_read_time, post_read_time, time_diff, total_time_diff= 0;
 2825  double last_abort_file_time= 0;
 2826  void *ctx= NULL;
 2827  char md5[16];
 2828  size_t data_size;
 2829  struct xorriso_md5_state state;
 2830  int num_chunks, async_md5;
 2831  static off_t chunks_limit= 256 * 1024 * 1024;
 2832 
 2833  memset(&state, 0, sizeof(state));
 2834  state.chunk= NULL;
 2835  state.chunk_state= NULL;
 2836  state.chunk_fill= NULL;
 2837  state.chunk_lba= NULL;
 2838  state.spotlist= spotlist;
 2839 
 2840  if(read_chunk > 1024)
 2841    read_chunk= 1024;
 2842  else if(read_chunk < 1)
 2843    read_chunk= 1;
 2844 
 2845  data_skip= job->data_to_skip;
 2846  num_chunks= job->async_chunks;
 2847  if(((off_t) num_chunks) * ((off_t) read_chunk) > chunks_limit)
 2848    num_chunks= chunks_limit / read_chunk;
 2849  async_md5= (num_chunks >= 2);
 2850 
 2851  if(async_md5)
 2852    data_size= num_chunks * read_chunk * 2048;
 2853  else
 2854    data_size= read_chunk * 2048;
 2855  Xorriso_alloc_meM(data, char, data_size);
 2856  data_pt= data;
 2857 
 2858  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 2859                                 "on attempt to check media readability",
 2860                                 2 * !!job->use_dev);
 2861  if(ret<=0)
 2862    goto ex;
 2863  ret= burn_disc_get_profile(drive, &profile_no, profile_name);
 2864  if(ret > 0) {
 2865    if(profile_no >= 0x08 && profile_no <= 0x0a) {
 2866      is_cd= 1;
 2867      eccb_size= 1;
 2868    } else if(profile_no >= 0x40 && profile_no <= 0x43) {
 2869      eccb_size= 32;
 2870    } else if(burn_drive_get_drive_role(drive) != 1) {
 2871      eccb_size= 1;
 2872    }
 2873  }
 2874 
 2875  if(job->sector_map != NULL) {
 2876    Sectorbitmap_get_layout(job->sector_map, &sectors, &sector_size, 0);
 2877    sector_size/= 2048;
 2878  }
 2879 
 2880  if(job->retry > 0)
 2881    retry= 1;
 2882  else if(job->retry == 0 && is_cd)
 2883    retry= 1;
 2884 
 2885  if(flag & 4) {
 2886    ret= iso_md5_start(&ctx);
 2887    if(ret < 0) {
 2888      Xorriso_no_malloc_memory(xorriso, NULL, 0);
 2889      ret= -1; goto ex;
 2890    }
 2891  }
 2892 
 2893  state.xorriso= xorriso;
 2894  state.ctx= ctx;
 2895  state.spotlist= spotlist;
 2896  state.md5_start= md5_start;
 2897  state.next_tag= 0;
 2898  state.chain_broken= 0;
 2899  state.in_track_gap= 0;
 2900  state.was_sb_tag= 0;
 2901  state.md5_spot_value= Xorriso_read_quality_untesteD;
 2902  state.md5_spot_lba= 0;
 2903  state.slave_state= 0;
 2904  state.chunk_size= read_chunk;
 2905  if(async_md5) {
 2906    state.num_chunks= num_chunks;
 2907    Xorriso_alloc_meM(state.chunk, char *, num_chunks);
 2908    Xorriso_alloc_meM(state.chunk_state, int, num_chunks);
 2909    Xorriso_alloc_meM(state.chunk_fill, int, num_chunks);
 2910    Xorriso_alloc_meM(state.chunk_lba, uint32_t, num_chunks);
 2911    for(i= 0; i < state.num_chunks; i++) {
 2912      state.chunk[i]= data + read_chunk * i * 2048;
 2913      state.chunk_state[i]= 0;
 2914      state.chunk_fill[i]= 0;
 2915      state.chunk_lba[i]= 0;
 2916    }
 2917    ret= pthread_mutex_init(&(state.spot_mutex), NULL);
 2918    if(ret != 0) {
 2919      sprintf(xorriso->info_text,
 2920              "-check_media: Cannot initialize thread mutex");
 2921      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
 2922      goto ex;
 2923    }
 2924  } else
 2925    state.num_chunks= 0;
 2926  state.chunk_w_idx= 0;
 2927  state.chunk_r_idx= 0;
 2928  state.w_sleeps= 0;
 2929  state.r_sleeps= 0;
 2930 
 2931  if(async_md5) {
 2932    ret= Xorriso_start_chunk_md5(xorriso, &state, 0);
 2933    if(ret <= 0)
 2934      goto ex;
 2935  }
 2936 
 2937  if(xorriso->read_speed_force > 0) /* initialize forced speed limit */
 2938    burn_nominal_slowdown(xorriso->read_speed_force, xorriso->read_speed_corr,
 2939                          &prev_time, &us_corr, (off_t) 0, 1);
 2940  Xorriso_set_speed(xorriso, drive, xorriso->read_speed, 0, 1);
 2941  Xorriso_process_msg_queues(xorriso,0);
 2942  start_lba= from_lba;
 2943  to_read= read_chunk;
 2944  post_read_time= Sfile_microtime(0);
 2945  for(i= 0; i < block_count; i+= to_read) {
 2946    if(i != 0)
 2947      data_skip= 0;
 2948    skip_reading= 0;
 2949    ret= Xorriso_check_for_abort(xorriso, job->abort_file_path, post_read_time,
 2950                                 &last_abort_file_time, 0);
 2951    if(ret == 1)
 2952      goto abort_check;
 2953    if(job->item_limit > 0 &&
 2954       Spotlist_count(spotlist, 0) + 2 >= job->item_limit) {
 2955      sprintf(xorriso->info_text, "-check_media: Reached item_limit=%d",
 2956              job->item_limit);
 2957      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
 2958      goto abort_check;
 2959    }
 2960    pre_read_time= Sfile_microtime(0);
 2961    if(job->time_limit > 0
 2962      && job->start_time + job->time_limit < pre_read_time) {
 2963      sprintf(xorriso->info_text, "-check_media: Reached time_limit=%d",
 2964              job->time_limit);
 2965      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
 2966 abort_check:;
 2967      if(prev_quality >= 0) {
 2968        ret= Xorriso__add_spot(&state, start_lba, i + from_lba - start_lba,
 2969                               prev_quality, 0);
 2970        if(ret <= 0)
 2971          goto ex;
 2972      }
 2973      ret= Xorriso__add_spot(&state, i + from_lba, block_count - i,
 2974                             Xorriso_read_quality_untesteD, 0);
 2975      if(ret > 0)
 2976        ret= 2;
 2977      goto ex;
 2978    }
 2979 
 2980    to_read= read_chunk;
 2981    skipped_to_read= 0;
 2982    suspect_tao_end= 0;
 2983    if(i + to_read > block_count)
 2984      to_read= block_count - i;
 2985    if(is_cd && i + to_read + 2 >= block_count) {
 2986      /* Read last 2 blocks of CD track separately, because with TAO tracks
 2987         they are always unreadable but with SAO tracks they contain data.
 2988      */
 2989      if(to_read > 2) {
 2990        to_read-= 2;
 2991      } else {
 2992        if(to_read > 1)
 2993          to_read--;
 2994        suspect_tao_end= 1;
 2995      }
 2996    }
 2997 
 2998    if(sector_size == read_chunk && from_lba % read_chunk == 0 
 2999       && !skip_reading) {
 3000      if(Sectorbitmap_is_set(job->sector_map, (i + from_lba) / sector_size, 0)){
 3001        quality= Xorriso_read_quality_valiD;
 3002        skip_reading= 1;
 3003      }
 3004    } else if(sector_size > 0 && !skip_reading) {
 3005      start_sec= (i + from_lba) / sector_size;
 3006      end_sec= (i + to_read + from_lba) / sector_size;
 3007      first_value= Sectorbitmap_is_set(job->sector_map, start_sec, 0);
 3008      for(j= start_sec; j < end_sec; j++)
 3009        if(Sectorbitmap_is_set(job->sector_map, j, 0) != first_value)
 3010      break;
 3011      to_read= j * sector_size - i - from_lba;
 3012      skip_reading= !!first_value;
 3013      if(skip_reading)
 3014        quality= Xorriso_read_quality_valiD;
 3015    }
 3016 
 3017    if(skip_reading) {
 3018      pre_read_time= post_read_time= Sfile_microtime(0);
 3019      skipped_to_read= to_read;
 3020    } else {
 3021      data_count= 0;
 3022      pre_read_time= Sfile_microtime(0);
 3023 
 3024      if(async_md5) {
 3025        ret= Xorriso__wait_chunk_md5(&state, 1, 0);
 3026        if(ret <= 0)
 3027          goto ex;
 3028        data_pt= state.chunk[state.chunk_w_idx];
 3029      }
 3030      ret= burn_read_data(drive, ((off_t) (i + from_lba)) * (off_t) 2048,
 3031                      data_pt, to_read * (off_t) 2048, &data_count,
 3032                      (4 * !retry) | (16 * !!suspect_tao_end));
 3033      post_read_time= Sfile_microtime(0);
 3034      time_diff= post_read_time - pre_read_time;
 3035      total_time_diff+= time_diff;
 3036      total_count++;
 3037      if(ret <= 0) {
 3038        Xorriso_process_msg_queues(xorriso,0);
 3039        if(data_count / 2048 < to_read) {
 3040          if(data_count > 0 && retry) {
 3041            if(prev_quality >= 0) {
 3042              ret= Xorriso__add_spot(&state, start_lba,
 3043                                     i + from_lba - start_lba, prev_quality, 0);
 3044               if(ret <= 0)
 3045                 goto ex;
 3046            }
 3047            ret= Xorriso__add_spot(&state, i + from_lba, data_count / 2048,
 3048                                   Xorriso_read_quality_partiaL, 0);
 3049            if(ret <= 0)
 3050              goto ex;
 3051            start_lba= i + from_lba + data_count / 2048;
 3052            if(suspect_tao_end && ret == -3)
 3053              prev_quality= Xorriso_read_quality_tao_enD;
 3054            else
 3055              prev_quality= Xorriso_read_quality_unreadablE;
 3056          }
 3057          if(suspect_tao_end && ret == -3)
 3058            quality= Xorriso_read_quality_tao_enD;
 3059          else
 3060            quality= Xorriso_read_quality_unreadablE;
 3061          if(retry) /* skip one eccb_size */
 3062            to_read= data_count / 2048 + eccb_size;
 3063 
 3064        } else { /* (can hardly happen) */
 3065          quality= Xorriso_read_quality_partiaL;
 3066        }
 3067        fret= Xorriso_eval_problem_status(xorriso, ret, 1|2);
 3068        if(fret<0)
 3069          goto ex;
 3070      } else {
 3071        quality= Xorriso_read_quality_gooD;
 3072        if(time_diff > job->slow_threshold_seq && job->slow_threshold_seq > 0 &&
 3073           i > 0)
 3074          quality= Xorriso_read_quality_sloW;
 3075      }
 3076 
 3077      /* MD5 checksumming */
 3078      if(ctx != NULL) {
 3079        if(async_md5) {
 3080          state.chunk_fill[state.chunk_w_idx]= to_read;
 3081          state.chunk_lba[state.chunk_w_idx]= i + from_lba;
 3082          state.chunk_state[state.chunk_w_idx]= 1;
 3083          /* The MD5 thread will call Xorriso_chunk_md5() */
 3084 
 3085          state.chunk_w_idx= (state.chunk_w_idx + 1) % state.num_chunks;
 3086        } else {
 3087          ret= Xorriso_chunk_md5(xorriso, data_pt, to_read,
 3088                                 (uint32_t) (i + from_lba), &state, 0);
 3089          if(ret <= 0)
 3090            goto ex;
 3091        }
 3092      }
 3093 
 3094      write_amount= data_count - data_skip;
 3095      if(data_count > 0) {
 3096        read_count+= data_count - data_skip;
 3097        if(job->data_to_limit >= 0 && read_count > job->data_to_limit)
 3098          write_amount-= (read_count - job->data_to_limit);
 3099      }
 3100      if(xorriso->read_speed_force > 0) {
 3101        slowdown_count+= data_count;
 3102        if(slowdown_count >= 128 * 1024) {
 3103          burn_nominal_slowdown(xorriso->read_speed_force,
 3104                                xorriso->read_speed_corr,
 3105                                &prev_time, &us_corr, slowdown_count, 0);
 3106          slowdown_count= 0;
 3107        }
 3108      }
 3109      if(write_amount > 0) {
 3110        if(job->data_to_fd >= 0) {
 3111          seek_adr= ((off_t) (i + from_lba)) * (off_t) 2048 +
 3112                    job->data_to_skip + job->data_to_offset;
 3113          if(strcmp(job->data_to_path, "-") != 0) {
 3114            ret= lseek(job->data_to_fd, seek_adr, SEEK_SET);
 3115            if(ret == -1) {
 3116 failed_to_write:;
 3117              sprintf(xorriso->info_text,
 3118                      "Cannot write %d bytes to position %.f in ",
 3119                      (int) data_count, (double) seek_adr);
 3120              Text_shellsafe(job->data_to_path, xorriso->info_text, 1);
 3121              Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno,
 3122                                  "FAILURE", 0);
 3123              {ret= 0; goto ex;}
 3124            }
 3125          }
 3126          ret= write(job->data_to_fd, data_pt + data_skip, write_amount);
 3127          if(ret == -1)
 3128            goto failed_to_write;
 3129        }
 3130      }
 3131    }
 3132    if(quality != prev_quality) {
 3133      if(prev_quality >= 0) {
 3134        ret= Xorriso__add_spot(&state, start_lba,
 3135                               i + from_lba - start_lba, prev_quality, 0);
 3136        if(ret <= 0)
 3137          goto ex;
 3138      }
 3139      start_lba= i + from_lba;
 3140      prev_quality= quality;
 3141    }
 3142    if(!(flag & 2)) {
 3143      xorriso->pacifier_count+= to_read - skipped_to_read;
 3144      if(post_read_time - xorriso->last_update_time >=
 3145         xorriso->pacifier_interval)
 3146        Xorriso_pacifier_callback(xorriso, "blocks read",
 3147                  xorriso->pacifier_count, xorriso->pacifier_total, "",
 3148                  8 | 16 | (128 * (job->use_dev == 1)));
 3149    }
 3150  }
 3151  if(prev_quality >= 0) {
 3152    ret= Xorriso__add_spot(&state, start_lba,
 3153                           block_count + from_lba - start_lba, prev_quality, 0);
 3154    if(ret <= 0)
 3155      goto ex;
 3156  }
 3157 
 3158  /* <<< for calibration of quality */
 3159  if(total_count > 0) {
 3160    sprintf(xorriso->info_text, "Xorriso_check_interval: %.1f s / %d = %f",
 3161            total_time_diff, total_count, total_time_diff / total_count);
 3162    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
 3163  }
 3164 
 3165 
 3166  /* MD5 checksumming : register result */
 3167  if(async_md5) {
 3168    ret= Xorriso__end_slave_md5(&state, 10000, 0);
 3169    if(ret <= 0)
 3170      goto ex;
 3171  }
 3172 
 3173  /* >>> ??? allow chain_broken to be a match ? */
 3174 
 3175  if(state.next_tag > 0) {
 3176    sprintf(xorriso->info_text, "Missing announced MD5 tag: start=%d pos=%d",
 3177            state.md5_start, state.next_tag);
 3178    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 3179    state.md5_spot_value= Xorriso_read_quality_md5_mismatcH;
 3180    state.md5_spot_lba= state.next_tag;
 3181  }
 3182  if(state.md5_spot_value != Xorriso_read_quality_untesteD) {
 3183    ret= Xorriso__add_spot(&state, state.md5_start,
 3184                 state.md5_spot_lba - state.md5_start, state.md5_spot_value, 0);
 3185    if(ret <= 0)
 3186      goto ex;
 3187  }
 3188 
 3189  ret= 1;
 3190 ex:;
 3191  if(async_md5) {
 3192    Xorriso__end_slave_md5(&state, 10000, 0);
 3193    sprintf(xorriso->info_text,
 3194            "async_chunks=%d , chunk_size=%ds , w_sleeps: %.f , r_sleeps: %.f",
 3195            state.num_chunks, read_chunk, (double) state.w_sleeps,
 3196            (double) state.r_sleeps);
 3197    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
 3198    if(state.chunk != NULL)
 3199      pthread_mutex_destroy(&(state.spot_mutex));
 3200    Xorriso_free_meM(state.chunk);
 3201    Xorriso_free_meM(state.chunk_state);
 3202    Xorriso_free_meM(state.chunk_fill);
 3203    Xorriso_free_meM(state.chunk_lba);
 3204  }
 3205  Xorriso_free_meM(data);
 3206  if(state.ctx != NULL)
 3207    iso_md5_end(&(state.ctx), md5);
 3208 
 3209  return(ret);
 3210 }
 3211 
 3212 
 3213 int Xorriso_check_media(struct XorrisO *xorriso, struct SpotlisT **spotlist,
 3214                         struct CheckmediajoB *job, int flag)
 3215 {
 3216  int media_blocks= 0, read_chunk= 32, ret, mode, start_lba= 0;
 3217  int blocks, os_errno, i, j, last_track_end= -1, track_blocks, track_lba;
 3218  int num_sessions, num_tracks, declare_untested= 0, md5_start;
 3219  int read_capacity= -1, end_lba, hret, count, quality, profile_no;
 3220  int track_bad_claim= 0;
 3221  char *toc_info= NULL, profile_name[80], msg[160];
 3222  struct burn_drive *drive;
 3223  struct burn_drive_info *dinfo;
 3224  enum burn_disc_status s;
 3225  struct isoburn_toc_disc *isoburn_disc= NULL;
 3226  struct isoburn_toc_session **isoburn_sessions;
 3227  struct isoburn_toc_track **iso_burn_tracks;
 3228  struct burn_toc_entry isoburn_entry;
 3229  struct stat stbuf;
 3230  struct burn_multi_caps *caps= NULL;
 3231 
 3232  *spotlist= NULL;
 3233 
 3234  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 3235                                 "on attempt to check media readability",
 3236                                 2 * !!job->use_dev);
 3237  if(ret<=0)
 3238    goto ex;
 3239  
 3240  ret = burn_disc_get_profile(drive, &profile_no, profile_name);
 3241  if(ret <= 0)
 3242    profile_no= 0;
 3243 
 3244  if(job->min_block_size != 0)
 3245    read_chunk= job->min_block_size;
 3246 
 3247  ret= Spotlist_new(spotlist, 0);
 3248  if(ret <= 0)
 3249    {ret= -1; goto ex;}
 3250 
 3251  if(job->sector_map_path[0]) {
 3252    Sectorbitmap_destroy(&(job->sector_map), 0);
 3253    if(stat(job->sector_map_path, &stbuf) != -1) {
 3254      ret= Sectorbitmap_from_file(&(job->sector_map), job->sector_map_path,
 3255                                  xorriso->info_text, &os_errno, 0);
 3256      if(ret <= 0) {
 3257        if(xorriso->info_text[0])
 3258          Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, os_errno,
 3259                              "FAILURE", 0);
 3260        goto ex;
 3261      }
 3262    }
 3263    Xorriso_toc_to_string(xorriso, &toc_info,
 3264                          (2 * !!job->use_dev) | (4 * !job->map_with_volid));
 3265  }
 3266  ret= Xorriso_open_job_data_to(xorriso, job, 0);
 3267  if(ret <= 0)
 3268    goto ex;
 3269  Xorriso_pacifier_reset(xorriso, 0);
 3270  job->start_time= time(NULL);
 3271  mode= job->mode;
 3272  if(job->min_lba > 0) {
 3273    start_lba= job->min_lba;
 3274    ret= Spotlist_add_item(*spotlist, 0, job->min_lba, 
 3275                           Xorriso_read_quality_untesteD, 0);
 3276    if(ret <= 0)
 3277      goto ex;
 3278  }
 3279 
 3280  s= isoburn_disc_get_status(drive);
 3281  if(s != BURN_DISC_APPENDABLE && s != BURN_DISC_FULL) {
 3282    Xorriso_msgs_submit(xorriso, 0, "-check_media: No readable medium found",
 3283                        0, "SORRY", 0);
 3284    ret= 0; goto ex;
 3285  }
 3286 
 3287  ret= burn_get_read_capacity(drive, &read_capacity, 0);
 3288  if(ret <= 0)
 3289    read_capacity= -1;
 3290 
 3291  if(job->max_lba >= 0) {
 3292    blocks= job->max_lba + 1 - start_lba;
 3293    xorriso->pacifier_total= blocks;
 3294    ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks,
 3295                                read_chunk, 0, 0);
 3296    if(ret <= 0)
 3297      goto ex;
 3298    
 3299  } else if(mode == 0) { /* track by track */
 3300    isoburn_disc= isoburn_toc_drive_get_disc(drive);
 3301    if(isoburn_disc == NULL)
 3302      goto libburn_whole_disc;
 3303    isoburn_sessions=
 3304                     isoburn_toc_disc_get_sessions(isoburn_disc, &num_sessions);
 3305    for(i= 0; i < num_sessions; i++) {
 3306      iso_burn_tracks= isoburn_toc_session_get_tracks(isoburn_sessions[i],
 3307                                                      &num_tracks);
 3308      for(j= 0; j < num_tracks; j++) {
 3309        isoburn_toc_track_get_entry(iso_burn_tracks[j], &isoburn_entry);
 3310        if(!(isoburn_entry.extensions_valid & 1)) /* should not happen */
 3311      continue;
 3312        track_lba= isoburn_entry.start_lba;
 3313        track_blocks= isoburn_entry.track_blocks;
 3314 
 3315        /* The last track of an appendable BD-R reports more blocks than the
 3316           read capacity allows. All BD-R track sizes are multiple of 64 kB.
 3317        */
 3318        if (i == num_sessions - 1 && 
 3319            (track_lba + track_blocks > read_capacity &&
 3320             track_lba + track_blocks < read_capacity + 32 &&
 3321             (profile_no == 0x41 || profile_no == 0x40)))
 3322          track_blocks= read_capacity - track_lba;
 3323        if(track_lba + track_blocks > read_capacity) {
 3324          if(track_bad_claim < track_lba + track_blocks)
 3325            track_bad_claim= track_lba + track_blocks;
 3326          if(track_lba >= read_capacity) {
 3327            sprintf(msg, "-check_media: Track %d of session %d begins after end of readable medium area.",
 3328                    j + 1, i + 1);
 3329            Xorriso_msgs_submit(xorriso, 0, msg, 0, "WARNING", 0);
 3330      continue;
 3331          } else {
 3332 
 3333            if(profile_no >= 0x08 && profile_no <= 0x0a &&
 3334               track_lba + track_blocks == read_capacity + 2 &&
 3335               i == num_sessions - 1 && j == num_tracks - 1) {
 3336              sprintf(msg, "-check_media: Last CD track exceeds readable area by 2 blocks. Assuming TAO.");
 3337              Xorriso_msgs_submit(xorriso, 0, msg, 0, "DEBUG", 0);
 3338            } else {
 3339              sprintf(msg, "-check_media: Track %d of session %d extends over the end of readable medium area.",
 3340                    j + 1, i + 1);
 3341              Xorriso_msgs_submit(xorriso, 0, msg, 0, "WARNING", 0);
 3342            }
 3343            track_blocks= read_capacity - track_lba;
 3344          }
 3345        }
 3346        md5_start= track_lba;
 3347        if(i == 0 && j == 0) {
 3348          if(track_lba == 32) {
 3349            ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
 3350            if(ret > 0) {
 3351              if(caps->start_adr) {
 3352                /* block 0 to 31 are the overall mount entry of overwritable */
 3353                track_lba= 0;
 3354                track_blocks+= 32;
 3355              }
 3356            }
 3357          }
 3358        }
 3359        if(last_track_end >= 0 && last_track_end < track_lba &&
 3360           last_track_end >= start_lba) {
 3361          ret= Spotlist_add_item(*spotlist, last_track_end,
 3362                                 track_lba - last_track_end,
 3363                                 Xorriso_read_quality_off_tracK, 0);
 3364          if(ret <= 0)
 3365            goto ex;
 3366        }
 3367        last_track_end= track_lba + track_blocks;
 3368 
 3369        if(track_lba < start_lba) {
 3370          track_blocks-= start_lba - track_lba;
 3371          track_lba= start_lba;
 3372        }
 3373        if(track_blocks <= 0)
 3374      continue;
 3375        if(declare_untested) {
 3376          ret= Spotlist_add_item(*spotlist, track_lba, track_blocks,
 3377                                 Xorriso_read_quality_untesteD, 0);
 3378          if(ret <= 0)
 3379            goto ex;
 3380        } else {
 3381          ret= Xorriso_check_interval(xorriso, *spotlist, job, track_lba,
 3382                                      track_blocks, read_chunk, md5_start,
 3383                                      (i > 0) | (4 * (xorriso->do_md5 & 1)));
 3384          if(ret <= 0)
 3385            goto ex;
 3386          if(ret == 2)
 3387            declare_untested= 1;
 3388        }
 3389      }
 3390    }
 3391 
 3392    if(track_bad_claim > read_capacity) {
 3393      count= Spotlist_count(*spotlist, 0);
 3394      Spotlist_get_item(*spotlist, count - 1, &track_lba, &blocks, &quality, 0);
 3395      if(profile_no >= 0x08 && profile_no <= 0x0a &&
 3396         track_bad_claim - read_capacity == 2 &&
 3397         quality != Xorriso_read_quality_tao_enD)
 3398        quality= Xorriso_read_quality_tao_enD;
 3399      else
 3400        quality= Xorriso_read_quality_unreadablE;
 3401      ret= Spotlist_add_item(*spotlist, read_capacity,
 3402                             track_bad_claim - read_capacity, quality, 0);
 3403      if(ret <= 0)
 3404        goto ex;
 3405    }
 3406 
 3407  } else if(mode == 1) { /* Image range */
 3408    /* Default is the emulated disc capacity.
 3409    */
 3410    isoburn_disc= isoburn_toc_drive_get_disc(drive);
 3411    if(isoburn_disc == NULL)
 3412      goto libburn_whole_disc;
 3413    blocks= media_blocks= isoburn_toc_disc_get_sectors(isoburn_disc);
 3414 
 3415    /* If possible, determine the end address of the loaded ISO image.
 3416    */
 3417    track_lba= isoburn_get_attached_start_lba(drive);
 3418    if(track_lba >= 0) {
 3419      ret= isoburn_read_iso_head(drive, track_lba, &track_blocks, NULL, 0);
 3420      if(ret > 0) {
 3421        blocks= media_blocks= track_lba + track_blocks;
 3422      }
 3423    }
 3424 
 3425    if(start_lba >= 0)
 3426      blocks-= start_lba;
 3427    if(media_blocks <= 0)
 3428      goto libburn_whole_disc;
 3429    xorriso->pacifier_total= blocks;
 3430    ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks,
 3431                                read_chunk, 0, (4 * (xorriso->do_md5 & 1)));
 3432    if(ret <= 0)
 3433      goto ex;
 3434  } else if(mode == 2) {
 3435 libburn_whole_disc:;
 3436    /* single sweep over libburn medium capacity */
 3437    ret= burn_get_read_capacity(drive, &blocks, 0);
 3438    if(ret <= 0) {
 3439      Xorriso_process_msg_queues(xorriso,0);
 3440      sprintf(xorriso->info_text, "No content detected on media");
 3441      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 3442      {ret= 0; goto ex;}
 3443    }
 3444    blocks-= start_lba;
 3445    xorriso->pacifier_total= blocks;
 3446    ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks,
 3447                                read_chunk, 0, (4 * (xorriso->do_md5 & 1)));
 3448    if(ret <= 0)
 3449      goto ex;
 3450  }
 3451 
 3452  Xorriso_pacifier_callback(xorriso, "blocks read",
 3453                       xorriso->pacifier_count, xorriso->pacifier_total, "",
 3454                       1 | 8 | 16 | 32 | (128 * (job->use_dev == 1)));
 3455  ret= 1;
 3456 ex:;
 3457 
 3458  if(job->data_to_fd != -1 && strcmp(job->data_to_path, "-") != 0)
 3459    close(job->data_to_fd);
 3460  job->data_to_fd= -1;
 3461  
 3462  if(read_capacity >= 0) {
 3463    count= Spotlist_count(*spotlist, 0);
 3464    end_lba= 0;
 3465    for(i= 0; i < count; i++) {
 3466      Spotlist_get_item(*spotlist, i, &start_lba, &blocks, &quality, 0);
 3467      if(start_lba + blocks > end_lba)
 3468        end_lba= start_lba + blocks;
 3469    }
 3470    if(read_capacity > end_lba) {
 3471      hret= Spotlist_add_item(*spotlist, end_lba, read_capacity - end_lba, 
 3472                              Xorriso_read_quality_untesteD, 0);
 3473      if(hret < ret)
 3474        ret= hret;
 3475    }
 3476  }
 3477 
 3478  if(ret > 0)
 3479    ret= Xorriso_update_in_sector_map(xorriso, *spotlist, read_chunk, job, 0);
 3480  
 3481  if(ret > 0) {
 3482    ret= Xorriso_spotlist_to_sectormap(xorriso, *spotlist, read_chunk,
 3483                                       &(job->sector_map), 2);
 3484    if(ret > 0 && job->sector_map_path[0]) {
 3485      ret= Sectorbitmap_to_file(job->sector_map, job->sector_map_path, toc_info,
 3486                                xorriso->info_text, &os_errno, 0);
 3487      if(ret <= 0) {
 3488        if(xorriso->info_text[0])
 3489          Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, os_errno,
 3490                              "FAILURE", 0);
 3491      }
 3492    }
 3493  }
 3494  if(toc_info != NULL)
 3495     free(toc_info);
 3496  if(ret <= 0)
 3497    Spotlist_destroy(spotlist, 0);
 3498  if(caps!=NULL)
 3499    burn_disc_free_multi_caps(&caps);
 3500  if(isoburn_disc != NULL)
 3501    isoburn_toc_disc_free(isoburn_disc);
 3502  return(ret);
 3503 }
 3504 
 3505 
 3506 /* @param flag
 3507           bit0= if not MMC drive print NOTE and return 2  
 3508           bit1= obtain outdrive, else indrive
 3509           bit4= do not report failure
 3510 */
 3511 int Xorriso_get_drive_handles(struct XorrisO *xorriso,
 3512                               struct burn_drive_info **dinfo,
 3513                               struct burn_drive **drive,
 3514                               char *attempt, int flag)
 3515 {
 3516  int ret;
 3517 
 3518  if(flag&2)
 3519    *dinfo= (struct burn_drive_info *) xorriso->out_drive_handle;
 3520  else
 3521    *dinfo= (struct burn_drive_info *) xorriso->in_drive_handle;
 3522  if(*dinfo==NULL && !(flag & 16)) {
 3523    Xorriso_process_msg_queues(xorriso,0);
 3524    sprintf(xorriso->info_text, "No %s drive acquired %s",
 3525            (flag&2 ? "output" : "input"), attempt);
 3526    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 3527  }
 3528  if(*dinfo==NULL)
 3529    return(0);
 3530  *drive= (*dinfo)[0].drive;
 3531  if(flag & 1) {
 3532    ret= burn_drive_get_drive_role(*drive);
 3533    if(ret != 1) {
 3534      sprintf(xorriso->info_text,
 3535        "Output device is not an MMC drive. Desired operation does not apply.");
 3536      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
 3537      return(2);
 3538    }
 3539  }
 3540  return((*drive)!=NULL);
 3541 }
 3542 
 3543 
 3544 int Xorriso_pretend_full_disc(struct XorrisO *xorriso, int flag)
 3545 {
 3546  int ret;
 3547  struct burn_drive_info *dinfo;
 3548  struct burn_drive *drive;
 3549 
 3550  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 3551                 "on attempt to let libburn pretend having a closed medium", 2);
 3552  if(ret<=0)
 3553    return(ret);
 3554 
 3555  ret= isoburn_disc_pretend_full_uncond(drive);
 3556  Xorriso_process_msg_queues(xorriso,0);
 3557  if(ret <= 0) {
 3558    sprintf(xorriso->info_text,
 3559            "Failed to let libburn pretend having a closed medium");
 3560    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
 3561    return(0);
 3562  }
 3563  return(1);
 3564 }
 3565 
 3566 
 3567 int Xorriso_scsi_dev_family(struct XorrisO *xorriso, int flag)
 3568 {
 3569  burn_preset_device_open(xorriso->drives_exclusive | (xorriso->linux_scsi_dev_family << 2), 0, 0);
 3570  return(1);
 3571 }
 3572 
 3573 
 3574 int Xorriso_use_immed_bit(struct XorrisO *xorriso, int flag)
 3575 {
 3576  int enable= 1, ret;
 3577  struct burn_drive_info *dinfo;
 3578  struct burn_drive *drive;
 3579 
 3580  /* It is not an error if no drive is acquired.
 3581     Xorriso_drive_aquire() will apply use_immed_bit.
 3582  */
 3583  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 3584                 "on attempt to control use of Immed bit", 2 | 16);
 3585  if(ret<0)
 3586    return(ret);
 3587  if(ret == 0)
 3588    return(1);
 3589 
 3590  if(xorriso->use_immed_bit == -1) {
 3591    enable= 0;
 3592  } else if(xorriso->use_immed_bit == 1) {
 3593    enable= 1;
 3594  } else if(xorriso->use_immed_bit == 0) {
 3595    /* obtain default value as determined after drive aquiration */
 3596    if(xorriso->use_immed_bit_default == 0)
 3597      return(1);
 3598    enable= (xorriso->use_immed_bit_default > 0);
 3599  }
 3600  burn_drive_set_immed(drive, enable);
 3601  Xorriso_process_msg_queues(xorriso,0);
 3602  return(1);
 3603 }
 3604 
 3605 
 3606 int Xorriso_obtain_indev_readsize(struct XorrisO *xorriso, uint32_t *blocks,
 3607                                   int flag)
 3608 {
 3609  int ret, num_data;
 3610  struct burn_drive_info *dinfo;
 3611  struct burn_drive *drive;
 3612  enum burn_disc_status s;
 3613 
 3614  *blocks= 0;
 3615  ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
 3616                                 "on attempt to determine readable size", 0);
 3617  if(ret <= 0)
 3618    return(0);
 3619  s= isoburn_disc_get_status(drive);
 3620  if(s == BURN_DISC_BLANK)
 3621    return(1);
 3622  ret= burn_get_read_capacity(drive, &num_data, 0);
 3623  if(ret <= 0)
 3624    return(0);
 3625  *blocks= num_data;
 3626  return(1);
 3627 }
 3628 
 3629