• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

libisoburn-0.5.6.pl00/libisoburn/burn_wrap.c

Go to the documentation of this file.
00001 
00002 /*
00003    cc -g -c \
00004       -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
00005       burn_wrap.c
00006 */
00007 /* libburn wrappers for libisoburn 
00008 
00009    Copyright 2007 - 2010  Thomas Schmitt, <scdbackup@gmx.net> 
00010    Provided under GPL version 2 or later.
00011 */
00012 
00013 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo 
00014 #define Hardcoded_cd_rW 1
00015 #define Hardcoded_cd_rw_c1     12999
00016 #define Hardcoded_cd_rw_nwA   152660 
00017 */
00018 
00019 #include <stdio.h>
00020 #include <ctype.h>
00021 #include <sys/types.h>
00022 #include <unistd.h>
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 #include <time.h>
00028 #include <regex.h>
00029 
00030 
00031 #ifndef Xorriso_standalonE
00032 
00033 #include <libburn/libburn.h>
00034 
00035 #include <libisofs/libisofs.h>
00036 
00037 #else /* ! Xorriso_standalonE */
00038 
00039 #include "../libisofs/libisofs.h"
00040 #include "../libburn/libburn.h"
00041 
00042 #endif /* Xorriso_standalonE */
00043 
00044 
00045 #include "libisoburn.h"
00046 #include "isoburn.h"
00047 
00048 
00049 /* The global list of isoburn objects. Usually there is only one. */
00050 extern struct isoburn *isoburn_list_start; /* in isoburn.c */
00051 
00052 /* Default values for application provided msgs_submit methods.
00053    To be attached to newly aquired drives.
00054    Storage location is isoburn.c
00055 */
00056 extern int (*libisoburn_default_msgs_submit)
00057     (void *handle, int error_code, char msg_text[],
00058                  int os_errno, char severity[], int flag);
00059 extern void *libisoburn_default_msgs_submit_handle;
00060 extern int libisoburn_default_msgs_submit_flag;
00061 
00062 
00063 static int isoburn_emulate_toc(struct burn_drive *d, int flag);
00064 
00065 
00066 int isoburn_initialize(char msg[1024], int flag)
00067 {
00068  int major, minor, micro, bad_match= 0;
00069 
00070 
00071 /* First two ugly compile time checks for header version compatibility.
00072    If everthing matches, then they produce no C code. In case of mismatch,
00073    intentionally faulty C code will be inserted.
00074 */
00075 
00076 #ifdef iso_lib_header_version_major
00077 /* The minimum requirement of libisoburn towards the libisofs header
00078    at compile time is defined in libisoburn/libisoburn.h :
00079      isoburn_libisofs_req_major
00080      isoburn_libisofs_req_minor
00081      isoburn_libisofs_req_micro
00082    It gets compared against the version macros in libisofs/libisofs.h :
00083      iso_lib_header_version_major
00084      iso_lib_header_version_minor
00085      iso_lib_header_version_micro
00086    If the header is too old then the following code shall cause failure of
00087    libisoburn compilation rather than to allow production of a program with
00088    unpredictable bugs or memory corruption.
00089    The compiler messages supposed to appear in this case are:
00090       error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function)
00091       error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_AND_burn_wrap_dot_h' undeclared (first use in this function)
00092       error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function)
00093 */
00094 /* The indendation is an advise of man gcc to help old compilers ignoring */
00095  #if isoburn_libisofs_req_major > iso_lib_header_version_major
00096  #define Isoburn_libisofs_dot_h_too_olD 1
00097  #endif
00098  #if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor
00099  #define Isoburn_libisofs_dot_h_too_olD 1
00100  #endif
00101  #if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro
00102  #define Isoburn_libisofs_dot_h_too_olD 1
00103  #endif
00104 
00105 #ifdef Isoburn_libisofs_dot_h_too_olD
00106 LIBISOFS_MISCONFIGURATION = 0;
00107 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_AND_burn_wrap_dot_h = 0;
00108 LIBISOFS_MISCONFIGURATION_ = 0;
00109 #endif
00110 
00111 #endif /* iso_lib_header_version_major */
00112 
00113 /* The minimum requirement of libisoburn towards the libburn header
00114    at compile time is defined in libisoburn/libisoburn.h :
00115      isoburn_libburn_req_major
00116      isoburn_libburn_req_minor
00117      isoburn_libburn_req_micro
00118    It gets compared against the version macros in libburn/libburn.h :
00119      burn_header_version_major
00120      burn_header_version_minor
00121      burn_header_version_micro
00122    If the header is too old then the following code shall cause failure of
00123    cdrskin compilation rather than to allow production of a program with
00124    unpredictable bugs or memory corruption.
00125    The compiler messages supposed to appear in this case are:
00126       error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
00127       error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
00128       error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
00129 */
00130 
00131 /* The indendation is an advise of man gcc to help old compilers ignoring */
00132  #if isoburn_libburn_req_major > burn_header_version_major
00133  #define Isoburn_libburn_dot_h_too_olD 1
00134  #endif
00135  #if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor
00136  #define Isoburn_libburn_dot_h_too_olD 1
00137  #endif
00138  #if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro
00139  #define Isoburn_libburn_dot_h_too_olD 1
00140  #endif
00141 
00142 #ifdef Isoburn_libburn_dot_h_too_olD
00143 LIBBURN_MISCONFIGURATION = 0;
00144 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
00145 LIBBURN_MISCONFIGURATION_ = 0;
00146 #endif
00147 
00148 /* End of ugly compile time tests (scroll up for explanation) */
00149 
00150 
00151 
00152  msg[0]= 0;
00153  if(iso_init()<0) {
00154    sprintf(msg+strlen(msg), "Cannot initialize libisofs\n");
00155    return(0);
00156  }
00157  iso_lib_version(&major, &minor, &micro);
00158  sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro);
00159 #ifdef iso_lib_header_version_major
00160  if(iso_lib_is_compatible(iso_lib_header_version_major,
00161                           iso_lib_header_version_minor,
00162                           iso_lib_header_version_micro)) {
00163    sprintf(msg+strlen(msg), "ok, ");
00164  } else {
00165    sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
00166            iso_lib_header_version_major, iso_lib_header_version_minor,
00167            iso_lib_header_version_micro);
00168    bad_match= 1;
00169  }
00170 #else
00171  if(iso_lib_is_compatible(isoburn_libisofs_req_major,
00172                           isoburn_libisofs_req_minor,
00173                           isoburn_libisofs_req_micro)) {
00174    sprintf(msg+strlen(msg), "suspicious, ");
00175  } else {
00176    sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
00177            isoburn_libisofs_req_major, isoburn_libisofs_req_minor,
00178            isoburn_libisofs_req_micro);
00179    bad_match= 1;
00180  }
00181 #endif /* ! iso_lib_header_version_major */
00182 
00183  if(!burn_initialize()) {
00184    sprintf(msg+strlen(msg), "Cannot initialize libburn\n");
00185    return(0);
00186  }
00187  burn_version(&major, &minor, &micro);
00188  sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro);
00189  if(major > burn_header_version_major
00190     || (major == burn_header_version_major
00191         && (minor > burn_header_version_minor
00192             || (minor == burn_header_version_minor
00193                 && micro >= burn_header_version_micro)))) {
00194    sprintf(msg+strlen(msg), "ok, ");
00195  } else {
00196    sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n",
00197            burn_header_version_major, burn_header_version_minor,
00198            burn_header_version_micro);
00199    bad_match= 1;
00200  }
00201 
00202  isoburn_version(&major, &minor, &micro);
00203  sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro);
00204  if(bad_match)
00205    return(0);
00206 
00207  isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */
00208  return(1);
00209 }
00210 
00211 
00212 /* API @since 0.1.0 */
00213 int isoburn_libisofs_req(int *major, int *minor, int *micro)
00214 {
00215  *major= iso_lib_header_version_major;
00216  *minor= iso_lib_header_version_minor;
00217  *micro= iso_lib_header_version_micro;
00218  return(1);
00219 }
00220 
00221 
00222 /* API @since 0.1.0 */
00223 int isoburn_libburn_req(int *major, int *minor, int *micro)
00224 {
00225  *major= burn_header_version_major;
00226  *minor= burn_header_version_minor;
00227  *micro= burn_header_version_micro;
00228  return(1);
00229 }
00230 
00231 
00232 int isoburn_set_msgs_submit(int (*msgs_submit)(void *handle, int error_code,
00233                                                char msg_text[], int os_errno,
00234                                                char severity[], int flag),
00235                                void *submit_handle, int submit_flag, int flag)
00236 {
00237  libisoburn_default_msgs_submit= msgs_submit;
00238  libisoburn_default_msgs_submit_handle= submit_handle;
00239  libisoburn_default_msgs_submit_flag= submit_flag;
00240  return(1);
00241 }
00242 
00243 
00244 int isoburn_is_intermediate_dvd_rw(struct burn_drive *d, int flag)
00245 {
00246  int profile, ret= 0, format_status, num_formats;
00247  char profile_name[80];
00248  enum burn_disc_status s;
00249  off_t format_size= -1;
00250  unsigned bl_sas;
00251 
00252  s= isoburn_disc_get_status(d);
00253  ret= burn_disc_get_profile(d, &profile, profile_name);
00254  if(ret>0 && profile==0x13)
00255    ret= burn_disc_get_formats(d, &format_status, &format_size,
00256                               &bl_sas, &num_formats);
00257  if(ret>0 && profile==0x13 && s==BURN_DISC_BLANK &&
00258     format_status==BURN_FORMAT_IS_UNKNOWN)
00259    return(1);
00260  return(0);
00261 }
00262 
00263 
00264 /** Examines the media and sets appropriate emulation if needed.
00265     @param flag bit0= pretent blank on overwriteable media
00266                 bit3= if the drive reports a -ROM profile then try to read 
00267                       table of content by scanning for ISO image headers.
00268                 bit4= do not emulate TOC on overwriteable media
00269                 bit5= ignore ACL from external filesystems
00270                 bit6= ignore POSIX Extended Attributes from external filesystems
00271                 bit7= pretend -ROM and scan for table of content
00272 */ 
00273 static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
00274                                  int flag)
00275 {
00276  int ret, lba, nwa, profile, readonly= 0;
00277  struct burn_multi_caps *caps= NULL;
00278  struct isoburn_toc_entry *t;
00279  char profile_name[80];
00280  struct isoburn_toc_disc *disc= NULL;
00281  struct isoburn_toc_session **sessions;
00282  struct isoburn_toc_track **tracks;
00283  int num_sessions= 0, num_tracks= 0, track_count= 0, session_no= 0;
00284  char msg[80];
00285  enum burn_disc_status s;
00286 
00287  s= burn_disc_get_status(d);
00288  profile_name[0]= 0;
00289  ret= burn_disc_get_profile(d, &profile, profile_name);
00290  if(ret<=0)
00291    profile= 0x00;
00292  ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0);
00293  if(ret<0) /* == 0 is read-only media, but it is too early to reject it here */
00294    goto ex;
00295  if(ret==0 || (flag & 128))
00296    readonly= 1;
00297  if(flag & 128)
00298    flag = (flag & ~ 16) | 8;
00299    
00300  ret= isoburn_new(o, 0);
00301  if(ret<=0)
00302    goto ex;
00303  (*o)->drive= d;
00304  (*o)->msgs_submit= libisoburn_default_msgs_submit;
00305  (*o)->msgs_submit_handle= libisoburn_default_msgs_submit_handle;
00306  (*o)->msgs_submit_flag= libisoburn_default_msgs_submit_flag;
00307  iso_image_set_ignore_aclea((*o)->image, (flag >> 5 ) & 3);
00308 
00309 #ifdef Hardcoded_cd_rW
00310  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
00311  caps->start_adr= 0;
00312  (*o)->fabricated_disc_status= BURN_DISC_APPENDABLE;
00313 #endif
00314 
00315  if(caps->start_adr)
00316    (*o)->emulation_mode= 1;
00317  if(caps->start_adr && !readonly) {       /* set emulation to overwriteable */
00318    ret= isoburn_is_intermediate_dvd_rw(d, 0);
00319    if(ret>0) {
00320      (*o)->min_start_byte= 0;
00321      (*o)->nwa= 0;
00322      (*o)->zero_nwa= 0;
00323    }
00324    if(flag&1) {
00325      (*o)->nwa= (*o)->zero_nwa;
00326      (*o)->fabricated_disc_status= BURN_DISC_BLANK;
00327    } else {
00328      ret= isoburn_start_emulation(*o, 0);
00329      if(ret<=0) {
00330        (*o)->emulation_mode= -1;
00331        goto ex;
00332      }
00333      /* try to read emulated toc */
00334      ret= isoburn_emulate_toc(d, flag & 16);
00335      if(ret<0) {
00336        (*o)->emulation_mode= -1;
00337        goto ex;
00338      }
00339    }
00340  } else {
00341 
00342     /* >>> recognize unsuitable media (but allow read-only media) */;
00343 
00344    if(readonly && s != BURN_DISC_EMPTY) {
00345      (*o)->fabricated_disc_status= BURN_DISC_FULL;
00346      /* This might be overwriteable media in a -ROM drive.
00347         Pitfall:
00348         Multi-session media which bear a xorriso image for overwriteables
00349         in their first session would get a TOC of that first image rather
00350         than of the media.
00351         It is not possible to distinguish a BD-RE from a single session
00352         BD-R with an image for overwriteables. But as soon as the media
00353         bears 2 logical tracks it cannot be overwriteable.
00354         So count the number of tracks first.
00355      */
00356      disc= isoburn_toc_drive_get_disc(d);
00357      if(disc != NULL) {
00358        sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
00359        for(session_no= 0; session_no < num_sessions; session_no++) {
00360          tracks= isoburn_toc_session_get_tracks(sessions[session_no],
00361                                                 &num_tracks);
00362          track_count+= num_tracks;
00363        }
00364        isoburn_toc_disc_free(disc);
00365      }
00366 
00367      sprintf(msg, "ROM media has libburn track count = %d", track_count);
00368      isoburn_msgs_submit(*o, 0x00060000, msg, 0, "DEBUG", 0);
00369 
00370      if((flag & 16) || track_count >= 2) {
00371        ret= 0; /* toc emulation off, or not overwriteable */
00372      } else {
00373        ret= isoburn_emulate_toc(d, 1);
00374        if(ret<0)
00375          goto ex;
00376        else if(ret > 0)
00377          (*o)->emulation_mode= 1;
00378      }
00379      if(ret == 0 && (profile != 0x08 || (flag & 128)) && (flag & 8)) {
00380        /* This might also be multi-session media which do not
00381           get shown with a decent TOC.
00382           CD-R TOC (profile 0x08) can be trusted. Others not.
00383           Do a scan search of ISO headers.
00384        */
00385        ret= isoburn_emulate_toc(d, 1|2);
00386        if(ret<0)
00387          goto ex;
00388        if(ret>0) { /* point msc1 to last session */
00389          if((*o)->toc!=NULL) {
00390            for(t= (*o)->toc; t->next!=NULL; t= t->next);
00391             (*o)->fabricated_msc1= t->start_lba;
00392          }
00393        }
00394      }
00395    }
00396 #ifdef Hardcoded_cd_rW
00397    (*o)->nwa= Hardcoded_cd_rw_nwA;
00398 #else
00399    ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
00400    if(ret>0)
00401      (*o)->nwa= nwa;
00402 #endif
00403 
00404  }
00405 
00406  ret= 1;
00407 ex:
00408  if(caps!=NULL)
00409    burn_disc_free_multi_caps(&caps);
00410  return(ret);
00411 }
00412 
00413 
00414 /**
00415     @param flag bit0= load
00416                 bit1= regard overwriteable media as blank
00417                 bit2= if the drive is a regular disk file: truncate it to
00418                       the write start address
00419                 bit3= if the drive reports a -ROM profile then try to read 
00420                       table of content by scanning for ISO image headers.
00421                       (depending on media type and drive state this might 
00422                        help or it might make the resulting toc even worse)
00423                 bit4= do not emulate TOC on overwriteable media
00424                 bit5= ignore ACL from external filesystems
00425                 bit6= ignore POSIX Extended Attributes from external filesystems
00426                 bit7= pretend -ROM profile and scan for table of content
00427 */
00428 int isoburn_drive_aquire(struct burn_drive_info *drive_infos[],
00429                          char *adr, int flag)
00430 {
00431  int ret, drive_grabbed= 0;
00432  struct isoburn *o= NULL;
00433 
00434 #ifndef NIX
00435 
00436 /* <<< should be obsolete by new drive addressing of libburn-0.5.2 */
00437 /* >>> but helps with kernel 2.4 to use /dev/sr */
00438 
00439  int conv_ret;
00440  char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
00441 
00442  conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr);
00443  if(conv_ret<=0)
00444    strcpy(libburn_drive_adr, adr);
00445  ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, flag&1);
00446 
00447 #else
00448 
00449  ret= burn_drive_scan_and_grab(drive_infos, adr, flag & 1);
00450 
00451 #endif /* ! NIX */
00452 
00453  if(ret<=0)
00454    goto ex;
00455  drive_grabbed= 1;
00456  ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive,
00457                             (flag & (8 | 16 | 32 | 64 | 128)) | !!(flag&2));
00458  if(ret<=0)
00459    goto ex;
00460 
00461  if(flag&4) {
00462    ret= isoburn_find_emulator(&o, (*drive_infos)[0].drive, 0);
00463    if(ret>0 && o!=NULL)
00464      o->truncate= 1;
00465  }
00466 
00467  ret= 1;
00468 ex:
00469  if(ret<=0) {
00470    if(drive_grabbed)
00471      burn_drive_release((*drive_infos)[0].drive, 0);
00472    isoburn_destroy(&o, 0);
00473  }
00474  return(ret);
00475 }
00476 
00477 
00478 int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
00479                                 char *adr, int load)
00480 {
00481  int ret;
00482 
00483  ret= isoburn_drive_aquire(drive_infos, adr, !!load);
00484  return(ret);
00485 }
00486 
00487 
00488 int isoburn_drive_grab(struct burn_drive *drive, int load)
00489 {
00490  int ret;
00491  struct isoburn *o= NULL;
00492 
00493  ret= burn_drive_grab(drive, load);
00494  if(ret<=0)
00495    goto ex;
00496  ret= isoburn_welcome_media(&o, drive, 0);
00497  if(ret<=0)
00498    goto ex;
00499  
00500  ret= 1;
00501 ex:
00502  if(ret<=0)
00503    isoburn_destroy(&o,0);
00504  return(ret);
00505 }
00506 
00507 
00508 /** Retrieve media emulation and eventual isoburn emulator of drive.
00509     @return -1 unsuitable media, 0 generic media, 1 emulated media.
00510 */
00511 int isoburn_find_emulator(struct isoburn **pt,
00512                                  struct burn_drive *drive, int flag)
00513 {
00514  int ret;
00515 
00516  ret= isoburn_find_by_drive(pt, drive, 0);
00517  if(ret<=0)
00518    return(0);
00519  if((*pt)->emulation_mode==-1) {
00520    isoburn_msgs_submit(*pt, 0x00060000,
00521                     "Unsuitable drive and media state", 0, "FAILURE", 0);
00522    return(-1);
00523  }
00524  if((*pt)->emulation_mode==0)
00525    return(0);
00526  return(1);
00527 } 
00528 
00529 
00530 enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive)
00531 {
00532  int ret;
00533  struct isoburn *o;
00534 
00535  ret= isoburn_find_emulator(&o, drive, 0);
00536  if(ret<0)
00537    return(BURN_DISC_UNSUITABLE);
00538  if(o!=NULL)
00539    if(o->fabricated_disc_status!=BURN_DISC_UNREADY)
00540      return(o->fabricated_disc_status);
00541  if(ret==0)
00542    return(burn_disc_get_status(drive));
00543 
00544  /* emulated status */
00545  if(o->emulation_mode==-1)
00546    return(BURN_DISC_UNSUITABLE);
00547  if(o->nwa>o->zero_nwa)
00548    return(BURN_DISC_APPENDABLE);
00549  return(BURN_DISC_BLANK);
00550 }
00551 
00552 
00553 int isoburn_disc_erasable(struct burn_drive *d)
00554 {
00555  int ret;
00556  struct isoburn *o;
00557 
00558  ret= isoburn_find_emulator(&o, d, 0);
00559  if(ret>0)
00560    if(o->emulation_mode==1)
00561      return(1);
00562  return burn_disc_erasable(d);
00563 }
00564 
00565 
00566 void isoburn_disc_erase(struct burn_drive *drive, int fast)
00567 {
00568  int ret, do_pseudo_blank= 0;
00569  struct isoburn *o;
00570  enum burn_disc_status s;
00571  char zero_buffer[Libisoburn_target_head_sizE];
00572  struct burn_multi_caps *caps= NULL;
00573 
00574  ret= isoburn_find_emulator(&o, drive, 0);
00575  if(ret>0) {
00576    if(o->emulation_mode==-1) {
00577      /* To cause a negative reply with burn_drive_wrote_well() */
00578      burn_drive_cancel(drive);
00579      goto ex;
00580    }
00581 
00582    if(o->emulation_mode > 0) { /* might be readonly with emulated sessions */
00583      ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
00584      if(ret > 0 && caps->start_adr)
00585        do_pseudo_blank= 1;
00586    }
00587    if(do_pseudo_blank) {
00588      s= isoburn_disc_get_status(drive);
00589      if(s==BURN_DISC_FULL) { /* unknown data format in first 64 kB */
00590        memset(zero_buffer, 0, Libisoburn_target_head_sizE);
00591        ret= burn_random_access_write(drive, (off_t) 0, zero_buffer,
00592                                      (off_t) Libisoburn_target_head_sizE, 1);
00593      } else {
00594        ret= isoburn_invalidate_iso(o, 0);
00595      }
00596      if(ret<=0)
00597        burn_drive_cancel(drive); /* mark run as failure */
00598      goto ex;
00599    }
00600  }
00601  burn_disc_erase(drive, fast);
00602 ex:;
00603  if(caps!=NULL)
00604    burn_disc_free_multi_caps(&caps);
00605 }
00606 
00607 
00608 off_t isoburn_disc_available_space(struct burn_drive *d,
00609                                    struct burn_write_opts *opts)
00610 {
00611  int ret;
00612  struct isoburn *o;
00613  struct burn_write_opts *eff_opts= NULL, *local_opts= NULL;
00614  enum burn_disc_status s;
00615  off_t avail;
00616 
00617  eff_opts= opts;
00618  ret= isoburn_find_emulator(&o, d, 0);
00619  if(ret>0 && o!=NULL)
00620    if(o->emulation_mode!=0) {
00621      s= isoburn_disc_get_status(d);
00622      if(s==BURN_DISC_FULL) /* unknown data format in first 64 kB */
00623        return((off_t) 0);
00624      local_opts= burn_write_opts_new(d);
00625      eff_opts= local_opts;
00626      burn_write_opts_set_start_byte(eff_opts, ((off_t) o->nwa) * (off_t) 2048);
00627    }
00628  avail= burn_disc_available_space(d, eff_opts);
00629  if(local_opts!=NULL)
00630    burn_write_opts_free(local_opts);
00631  local_opts= NULL;
00632  return(avail);
00633 }
00634 
00635 
00636 int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba)
00637 {
00638  int ret;
00639  struct isoburn *o;
00640 
00641 #ifdef Hardcoded_cd_rW
00642  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
00643  *start_lba= Hardcoded_cd_rw_c1;
00644  return(1);
00645 #endif
00646 
00647  if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE &&
00648     isoburn_disc_get_status(d)!=BURN_DISC_FULL) {
00649    isoburn_msgs_submit(NULL, 0x00060000,
00650                        "Media contains no recognizable data", 0, "SORRY", 0);
00651    return(0);
00652  }
00653  ret= isoburn_find_emulator(&o, d, 0);
00654  if(ret<0)
00655    return(0);
00656  if(o->fabricated_msc1>=0) {
00657    *start_lba= o->fabricated_msc1;
00658    return(1);
00659  }
00660  if(ret>0) if(o->emulation_mode>0) {
00661    *start_lba= 0;
00662    return(1);
00663  }
00664  return(burn_disc_get_msc1(d, start_lba));
00665 }
00666 
00667 
00668 int isoburn_disc_track_lba_nwa(struct burn_drive *d,
00669                                struct burn_write_opts *opts,
00670                                int trackno, int *lba, int *nwa)
00671 {
00672  int ret;
00673  struct isoburn *o;
00674 
00675 #ifdef Hardcoded_cd_rW
00676  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
00677  *lba= Hardcoded_cd_rw_c1;
00678  *nwa= Hardcoded_cd_rw_nwA;
00679  return(1);
00680 #endif
00681 
00682  *nwa= *lba= 0;
00683  ret= isoburn_find_emulator(&o, d, 0);
00684  if(ret<0)
00685    return(0);
00686  if(ret>0) if(o->emulation_mode>0) {
00687    *lba= 0;
00688    *nwa= o->nwa;
00689    return(1);
00690  }
00691  if(burn_drive_get_drive_role(d) != 1)
00692    return(1);
00693  return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa));
00694 }
00695 
00696 
00697 int isoburn_get_msc2(struct isoburn *o,
00698                      struct burn_write_opts *opts, int *msc2, int flag)
00699 {
00700  int ret, lba, nwa;
00701 
00702  if(o->fabricated_msc2>=0)
00703    *msc2= o->fabricated_msc2;
00704  else {
00705    ret= isoburn_disc_track_lba_nwa(o->drive, opts, 0, &lba, &nwa);
00706    if(ret<=0)
00707      return(ret);
00708    *msc2= nwa;
00709  }
00710  return(1);
00711 }
00712 
00713 
00714 void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
00715 {
00716  int ret;
00717  off_t nwa= 0;
00718  struct isoburn *o;
00719  struct burn_drive *drive;
00720  char reasons[BURN_REASONS_LEN],msg[160+BURN_REASONS_LEN];
00721  char adr[BURN_DRIVE_ADR_LEN];
00722  enum burn_write_types write_type;
00723  struct stat stbuf;
00724 
00725  drive= burn_write_opts_get_drive(opts);
00726  ret= isoburn_find_emulator(&o, drive, 0);
00727  if(ret<0)
00728    return;
00729  if(o!=NULL) {
00730    o->wrote_well= -1;
00731    if(o->emulation_mode!=0) {
00732      burn_write_opts_set_multi(opts, 0);
00733      if(o->emulation_mode>0 && o->nwa >= 0) {
00734        nwa= o->nwa;
00735 
00736        /* This caters for unwritten formatted DVD-RW. They need to be written
00737           sequentially on the first use. Only written areas are random access.
00738           If the first session is not written to LBA 0, then re-opening of
00739           formatting and padding is needed. 
00740           This can be done. But when the track gets closed after padding,
00741           this lasts a long time. There is a high risk that an app will not
00742           poll the message queue while waiting for  isoburn_disc_write()  to
00743           return. The pacifier loop usually happens only afterwards.
00744           So automatic formatting might cause a nervous clueless user.
00745        */
00746        ret= isoburn_is_intermediate_dvd_rw(drive, 0);
00747        if(ret>0 && nwa>0 && nwa <= o->zero_nwa) {
00748          /* actually this should not happen since such media get recognized
00749             by isoburn_welcome_media and o->zero_nwa gets set to 0
00750          */
00751          sprintf(msg,
00752         "DVD-RW insufficiently formatted. (Intermediate State, size unknown)");
00753          isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
00754          sprintf(msg,
00755                 "It might help to first deformat it and then format it again");
00756          isoburn_msgs_submit(o, 0x00060000, msg, 0, "HINT", 0);
00757          burn_drive_cancel(drive); /* mark run as failure */
00758          return;
00759        }
00760        /* end of DVD-RW oriented check */
00761 
00762        burn_write_opts_set_start_byte(opts, nwa * (off_t) 2048);
00763      }
00764    }
00765  }
00766 
00767  write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
00768  if (write_type == BURN_WRITE_NONE) {
00769     sprintf(msg, "Failed to find a suitable write mode:\n%s", reasons);
00770     isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
00771     if(o!=NULL)
00772       o->wrote_well= 0;
00773     /* To cause a negative reply with burn_drive_wrote_well() */
00774     burn_drive_cancel(drive);
00775     return;
00776  }
00777 
00778  sprintf(reasons, "%d", (int) write_type);
00779  sprintf(msg, "Write_type = %s\n",
00780               (write_type == BURN_WRITE_SAO ? "SAO" :
00781               (write_type == BURN_WRITE_TAO ? "TAO" : reasons)));
00782  isoburn_msgs_submit(o, 0x00060000, msg, 0, "DEBUG", 0);
00783 
00784 #ifdef Hardcoded_cd_rW
00785  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
00786  fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA);
00787  burn_write_opts_set_start_byte(opts,
00788                  ((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048);
00789 #endif
00790 
00791  if(o->truncate) {
00792    ret= burn_drive_get_drive_role(drive);
00793    if(ret==2) {
00794      ret= burn_drive_d_get_adr(drive, adr);
00795      if(ret>0) {
00796        ret= lstat(adr, &stbuf);
00797        if(ret!=-1)
00798          if(S_ISREG(stbuf.st_mode))
00799            truncate(adr, nwa * (off_t) 2048);
00800      }
00801    }
00802  }
00803 
00804  burn_disc_write(opts, disc);
00805 }
00806 
00807 
00808 void isoburn_drive_release(struct burn_drive *drive, int eject)
00809 {
00810  int ret;
00811  struct isoburn *o;
00812 
00813  ret= isoburn_find_emulator(&o, drive, 0);
00814  if(ret<0)
00815    return;
00816  if(o!=NULL) {
00817    isoburn_destroy(&o, 0);
00818  }
00819  burn_drive_release(drive, eject);
00820 }
00821 
00822 
00823 void isoburn_finish(void)
00824 {
00825  isoburn_destroy_all(&isoburn_list_start, 0);
00826  burn_finish();
00827  iso_finish();
00828 }
00829 
00830 
00831 int isoburn_needs_emulation(struct burn_drive *drive)
00832 {
00833  int ret;
00834  struct isoburn *o;
00835  enum burn_disc_status s;
00836 
00837  s= isoburn_disc_get_status(drive);
00838  if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE)
00839    return(-1);
00840  ret= isoburn_find_emulator(&o, drive, 0);
00841  if(ret<0)
00842    return(-1);
00843  if(ret>0)
00844    if(o->emulation_mode>0)
00845      return(1);
00846  return(0);  
00847 }
00848 
00849 
00850 int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag)
00851 {
00852  int ret;
00853  struct burn_drive *drive = o->drive;
00854  struct burn_multi_caps *caps= NULL;
00855  
00856  ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
00857  if(ret<=0)
00858    goto ex;
00859  if(!caps->start_adr) {
00860    isoburn_msgs_submit(o, 0x00060000,
00861                        "Cannot set start byte address with this type of media",
00862                        0, "FAILURE", 0);
00863    {ret= 0; goto ex;}
00864  }
00865  o->min_start_byte= value;
00866  if(value % caps->start_alignment)
00867    value+= caps->start_alignment - (value % caps->start_alignment);
00868  o->nwa= value/2048;
00869  /* If suitable for media alignment, round up to Libisoburn_nwa_alignemenT */
00870  if((o->nwa % Libisoburn_nwa_alignemenT) &&
00871      ((Libisoburn_nwa_alignemenT*2048) % caps->start_alignment)==0 )
00872    o->nwa+= Libisoburn_nwa_alignemenT - (o->nwa % Libisoburn_nwa_alignemenT);
00873  ret= 1;
00874 ex:
00875  if(caps!=NULL)
00876    burn_disc_free_multi_caps(&caps);
00877  return(ret);
00878 }
00879 
00880 
00881 int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
00882                                int flag)
00883 {
00884  int ret;
00885  struct isoburn *o;
00886 
00887  ret= isoburn_find_emulator(&o, d, 0);
00888  if(ret<0)
00889    return(-1);
00890  if(ret==0) 
00891    return(0);
00892  *start_byte= o->min_start_byte;
00893  if(o->min_start_byte<=0)
00894    return(0);
00895  return(1);
00896 }
00897 
00898 
00899 int isoburn_drive_wrote_well(struct burn_drive *d)
00900 {
00901  int ret;
00902  struct isoburn *o;
00903  
00904  ret= isoburn_find_emulator(&o, d, 0);
00905  if(ret<0)
00906    return(-1);
00907  if(o!=NULL)
00908    if(o->wrote_well>=0)
00909      return(o->wrote_well);
00910  ret= burn_drive_wrote_well(d);
00911  return ret;
00912 }
00913 
00914 
00915 int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
00916                 char **status_text)
00917 {
00918  int ret;
00919  struct isoburn *o;
00920  size_t hsize= 0, hfree_bytes= 0;
00921 
00922  ret= isoburn_find_emulator(&o, d, 0);
00923  if(ret<0)
00924    return(-1);
00925 
00926  if(o==NULL)
00927    return(-1);
00928  if(o->iso_source==NULL)
00929    return(-1);
00930  ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes);
00931  if(hsize > 1024*1024*1024)
00932    *size= 1024*1024*1024;
00933  else
00934    *size= hsize;
00935  if(hfree_bytes > 1024*1024*1024)
00936    *free_bytes= 1024*1024*1024;
00937  else
00938    *free_bytes= hfree_bytes;
00939  *status_text= "";
00940  if(ret==0)
00941    *status_text= "standby";
00942  else if(ret==1)
00943    *status_text= "active";
00944  else if(ret==2)
00945    *status_text= "ending";
00946  else if(ret==3)
00947    *status_text= "failing";
00948  else if(ret==4)
00949    *status_text= "unused";
00950  else if(ret==5)
00951    *status_text= "abandoned";
00952  else if(ret==6)
00953    *status_text= "ended";
00954  else if(ret==7)
00955    *status_text= "aborted";
00956  return(ret);
00957 }
00958 
00959 
00960 /* @param flag bit0= -reserved-
00961                bit1= this is a libburn severity
00962 */
00963 int isoburn__sev_to_text(int severity, char **severity_name,
00964                          int flag)
00965 {
00966  int ret;
00967    
00968  ret= iso_sev_to_text(severity, severity_name);
00969  if(ret>0)
00970    return(ret);
00971  ret= burn_sev_to_text(severity, severity_name, 0);
00972  return(ret);
00973 }
00974 
00975 
00976 int isoburn__text_to_sev(char *severity_name, int *severity_number, int flag)
00977 {
00978  int ret= 1;
00979 
00980  ret= iso_text_to_sev(severity_name, severity_number);
00981  if(ret>0)
00982    return(ret);
00983  ret= burn_text_to_sev(severity_name, severity_number, 0);
00984  return(ret);
00985 }
00986 
00987 
00988 int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
00989                              char min_severity[], int flag)
00990 {
00991  int error_code, iso_sev, min_sev, ret;
00992  char *sev_text_pt, *msg_text_pt= NULL;
00993 
00994  error_code= iso_error_get_code(iso_error_code);
00995  if(error_code < 0x00030000 || error_code >= 0x00040000)
00996    error_code= (error_code & 0xffff) | 0x00050000;
00997 
00998  if(iso_error_code<0)
00999    msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
01000  if(msg_text_pt==NULL)
01001    msg_text_pt= msg_text;
01002  iso_sev= iso_error_get_severity(iso_error_code);
01003  sev_text_pt= min_severity;
01004  isoburn__text_to_sev(min_severity, &min_sev, 0);
01005  if(min_sev < iso_sev) 
01006    isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
01007  ret= iso_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, 0);
01008  return(ret);
01009 }
01010 
01011 
01012 /* @param flag bit0-7: info return mode
01013                  0= do not return anything in info (do not even touch it)
01014                  1= copy volume id to info (info needs 33 bytes)
01015                  2= do not touch info (caller will copy 64 kB header to it)
01016                bit14= -reserved -
01017                bit15= -reserved-
01018    @return 1 seems to be a valid ISO image , 0 format not recognized, <0 error
01019 */
01020 int isoburn_read_iso_head_parse(struct burn_drive *d, unsigned char *data,
01021                                 int *image_blocks, char *info, int flag)
01022 {
01023  int i, info_mode;
01024 
01025  /* is this an ISO image ? */
01026  if(data[0]!=1)
01027    return(0);
01028  if(strncmp((char *) (data+1),"CD001",5)!=0)
01029    return(0);
01030  /* believe so */
01031 
01032  *image_blocks= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24);
01033  info_mode= flag&255;
01034  if(info_mode==0) {
01035    ;
01036  } else if(info_mode==1) {
01037    strncpy(info, (char *) (data+40), 32);
01038    info[32]= 0;
01039    for(i= strlen(info)-1; i>=0; i--)
01040      if(info[i]!=' ')
01041    break;
01042      else
01043        info[i]= 0;
01044  } else if(info_mode==2) {
01045    ;
01046  } else {
01047    isoburn_msgs_submit(NULL, 0x00060000,
01048                "Program error: Unknown info mode with isoburn_read_iso_head()",
01049                0, "FATAL", 0);
01050    return(-1);
01051  }
01052  return(1);
01053 }
01054                          
01055 
01056 /* API
01057    @param flag bit0-7: info return mode
01058                  0= do not return anything in info (do not even touch it)
01059                  1= copy volume id to info (info needs 33 bytes)
01060                  2= copy 64 kB header to info (needs 65536 bytes)
01061                bit13= do not read head from media but use first 64 kB from info
01062                bit14= check both half buffers (not only second)
01063                       return 2 if found in first block
01064                bit15= return-1 on read error
01065    @return 1 seems to be a valid ISO image , 2 found in first half buffer,
01066            0 format not recognized, <0 error
01067 */
01068 int isoburn_read_iso_head(struct burn_drive *d, int lba,
01069                           int *image_blocks, char *info, int flag)
01070 {
01071  unsigned char buffer[64*1024];
01072  int ret, info_mode, capacity, role;
01073  off_t data_count, to_read;
01074 
01075  info_mode= flag&255;
01076  *image_blocks= 0;
01077  if(flag&(1<<13)) {
01078    memcpy(buffer, info, 64*1024);
01079  } else {
01080    role = burn_drive_get_drive_role(d);
01081    ret = burn_get_read_capacity(d, &capacity, 0);
01082    if (ret <= 0 && role == 2) {
01083      /* Might be a block device on a system where libburn cannot determine its
01084         size.  Try to read anyway. */
01085      capacity = 0x7ffffff0;
01086      ret = 1;
01087    }
01088    memset(buffer, 0, 64 * 1024);
01089    to_read= (off_t) capacity * ((off_t) 2048);
01090    if(ret > 0 && to_read >= (off_t) (36 * 1024)) {
01091      if(to_read >= (off_t) (64 * 1024))
01092        to_read= 64 * 1024;
01093      ret = burn_read_data(d, ((off_t) lba) * (off_t) 2048, (char *) buffer,
01094                       to_read, &data_count, 2); /* no error messages */
01095    } else
01096      ret= 0;
01097    if(ret<=0)
01098      return(-1*!!(flag&(1<<15)));
01099    if(info_mode==2)
01100      memcpy(info, buffer, 64*1024);
01101  }
01102 
01103  if(flag&(1<<14)) {
01104    ret= isoburn_read_iso_head_parse(d, buffer, image_blocks, info, info_mode);
01105    if(ret<0)
01106      return(ret);
01107    if(ret>0)
01108      return(2);
01109  }
01110  ret= isoburn_read_iso_head_parse(d, buffer+32*1024, image_blocks, info,
01111                                   info_mode);
01112  if(ret<=0)
01113    return(ret);
01114  return(1);
01115 }
01116 
01117 
01118 int isoburn_make_toc_entry(struct isoburn *o, int *session_count, int lba,
01119                            int track_blocks, char *volid, int flag)
01120 {
01121  int ret;
01122  struct isoburn_toc_entry *item;
01123 
01124  ret= isoburn_toc_entry_new(&item, o->toc, 0);
01125  if(ret<=0) {
01126 no_memory:;
01127    isoburn_msgs_submit(o, 0x00060000,
01128                        "Not enough memory for emulated TOC entry object",
01129                        0, "FATAL", 0);
01130    return(-1);
01131  }
01132  if(o->toc==NULL)
01133    o->toc= item;
01134  (*session_count)++;
01135  item->session= *session_count;
01136  item->track_no= *session_count;
01137  item->start_lba= lba;
01138  item->track_blocks= track_blocks;
01139  if(volid != NULL) {
01140    item->volid= strdup(volid);
01141    if(item->volid == NULL)
01142      goto no_memory;
01143  }
01144  return(1);
01145 }
01146 
01147 
01148 /* @param flag bit0= allow unemulated media
01149                bit1= free scanning without enclosing LBA-0-header 
01150                bit4= represent emulated media as one single session
01151                      (not with bit1)
01152    @return -1 severe error, 0= no neat header chain, 1= credible chain read
01153 */
01154 int isoburn_emulate_toc(struct burn_drive *d, int flag)
01155 {
01156  int ret, image_size= 0, lba, track_blocks, session_count= 0, read_flag= 0;
01157  int scan_start= 0, scan_count= 0, probe_minus_16= 0, growisofs_nwa, role;
01158  int with_enclosure= 0, readable_blocks= -1;
01159  struct isoburn *o;
01160  char msg[160], size_text[80], *sev, volid[33], *volid_pt= NULL;
01161  time_t start_time, last_pacifier, now;
01162  
01163  /* is the media emulated multi-session ? */
01164  ret= isoburn_find_emulator(&o, d, 0);
01165  if(ret<0)
01166    return(-1);
01167  if(o==NULL)
01168    return(-1);
01169  if(o->emulation_mode<=0 && !(flag&1))
01170    return(0);
01171 
01172  ret= burn_get_read_capacity(d, &readable_blocks, 0);
01173  if(ret <= 0) {
01174 
01175    role = burn_drive_get_drive_role(d);
01176    if (role == 2)
01177      /* Might be a block device on a system where libburn cannot determine its
01178         size.  Try to read anyway. */
01179      readable_blocks= 0x7ffffff0; /* try to read anyway */
01180    else
01181      readable_blocks= -1;
01182  }
01183 
01184  start_time= last_pacifier= time(NULL);
01185  lba= 0;
01186  if(!(flag&2)) {
01187    ret= isoburn_read_iso_head(d, lba, &image_size, NULL, 0);
01188    if(ret<=0)
01189      {ret= 0; goto failure;}
01190    lba= Libisoburn_overwriteable_starT;
01191    with_enclosure= 1;
01192    if((flag & 16) && o->emulation_mode == 1) {
01193      ret= 1;
01194      goto failure; /* This will represent the media as single session */
01195    }
01196  }
01197  while(lba<image_size || (flag&2)) {
01198    now= time(NULL);
01199    if(now - last_pacifier >= 5) {
01200      last_pacifier= now;
01201      if(scan_count>=10*512)
01202        sprintf(size_text, "%.f MB", ((double) scan_count) / 512.0);
01203      else
01204        sprintf(size_text, "%.f kB", 2 * (double) scan_count);
01205      sprintf(msg, "Found %d ISO sessions by scanning %s in %.f seconds",
01206              session_count, size_text, (double) (now - start_time));
01207      isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
01208    }
01209    read_flag= 1;
01210    if(flag&2)
01211      read_flag|= (1<<15)|((session_count>0)<<14);
01212    else {
01213 
01214      /* growisofs aligns to 16 rather than 32. Overwriteable TOC emulation
01215         relies on not accidentially seeing inter-session trash data.
01216         But one can safely access 16 blocks earlier because a xorriso header
01217         would have overwritten with the unused 16 blocks at its start.
01218         If libisoburn alignment would increase, then this would not be
01219         possible any more.
01220      */
01221 
01222      if(probe_minus_16)
01223        read_flag|= (1<<14);
01224      probe_minus_16= 0;
01225    }
01226 
01227    ret= isoburn_read_iso_head(d, lba, &track_blocks, volid, read_flag);
01228    if(ret > 0) {
01229      volid_pt= volid;
01230    } else {
01231      volid_pt= NULL;
01232      if(session_count>0) {
01233        if(flag&2) {
01234          if(ret==0) {
01235            /* try at next 64 k block (check both 32 k halves) */
01236            lba+= 32;
01237            scan_count+= 32;
01238            if(lba-scan_start <= Libisoburn_toc_scan_max_gaP)
01239  continue;
01240          }
01241  break;
01242        }
01243        sprintf(msg,
01244                "Chain of ISO session headers broken at #%d, LBA %ds",
01245                session_count+1, lba);
01246        isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
01247 
01248        if(with_enclosure) {
01249          ret= isoburn_make_toc_entry(o, &session_count, 0, image_size, NULL,0);
01250          if(ret<=0)
01251            goto failure;
01252        }
01253  break; /* do not return failure */
01254 
01255      }
01256      {ret= 0; goto failure;}
01257    }
01258    if(ret==2) /* ISO header was found in first half block */
01259      lba-= 16;
01260 
01261    if(readable_blocks >= 0 && lba + track_blocks > readable_blocks) {
01262      sprintf(msg, "ISO image size %ds larger than readable size %ds",
01263                   lba + track_blocks, readable_blocks);
01264      isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
01265      track_blocks= readable_blocks - lba;
01266    }
01267    ret= isoburn_make_toc_entry(o, &session_count, lba, track_blocks, volid_pt,
01268                                0);
01269    if(ret<=0)
01270      goto failure;
01271    lba+= track_blocks;
01272    scan_count+= 32;
01273 
01274    /* growisofs aligns to 16 rather than 32 */
01275    growisofs_nwa= lba;
01276    if(growisofs_nwa % 16)
01277      growisofs_nwa+= 16 - (growisofs_nwa % 16);
01278    if(lba % Libisoburn_nwa_alignemenT)
01279      lba+= Libisoburn_nwa_alignemenT - (lba % Libisoburn_nwa_alignemenT);
01280    scan_start= lba;
01281    if(lba - growisofs_nwa == 16)
01282      probe_minus_16= 1;
01283  }
01284  if(last_pacifier != start_time)
01285    sev= "UPDATE";
01286  else
01287    sev= "DEBUG";
01288  now= time(NULL);
01289  if(scan_count>=10*512)
01290    sprintf(size_text, "%.f MB", ((double) scan_count) / 512.0);
01291  else
01292    sprintf(size_text, "%.f kB", 2 * (double) scan_count);
01293  sprintf(msg, "Found %d ISO sessions by scanning %s in %.f seconds",
01294          session_count, size_text, (double) (now - start_time));
01295  isoburn_msgs_submit(o, 0x00060000, msg, 0, sev, 0);
01296  return(1);
01297 failure:;
01298  isoburn_toc_entry_destroy(&(o->toc), 1);
01299  if(with_enclosure && o->emulation_mode == 1) {
01300    if(readable_blocks >= 0 && image_size > readable_blocks) {
01301      sprintf(msg, "ISO image size %ds larger than readable size %ds",
01302                   image_size, readable_blocks);
01303      isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
01304      image_size= readable_blocks;
01305    }
01306    session_count= 0;
01307    ret= isoburn_make_toc_entry(o, &session_count, 0, image_size, NULL, 0);
01308  }
01309  return(ret);
01310 }
01311 
01312 
01313 int isoburn_toc_new_arrays(struct isoburn_toc_disc *o,
01314                            int session_count, int track_count, int flag)
01315 {
01316  int i;
01317  int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag);
01318 
01319  o->sessions= calloc(session_count, sizeof(struct isoburn_toc_session));
01320  o->session_pointers=
01321                    calloc(session_count, sizeof(struct isoburn_toc_session *));
01322  o->tracks= calloc(track_count, sizeof(struct isoburn_toc_track));
01323  o->track_pointers= calloc(track_count, sizeof(struct isoburn_toc_track *));
01324  if(o->sessions!=NULL && o->session_pointers!=NULL &&
01325     o->tracks!=NULL && o->track_pointers!=NULL) {
01326    for(i= 0; i<session_count; i++) {
01327      o->sessions[i].session= NULL;
01328      o->sessions[i].track_pointers= NULL;
01329      o->sessions[i].track_count= 0;
01330      o->sessions[i].toc_entry= NULL;
01331      o->session_pointers[i]= NULL;
01332    }
01333    for(i= 0; i<track_count; i++) {
01334      o->tracks[i].track= NULL;
01335      o->tracks[i].toc_entry= NULL;
01336      o->track_pointers[i]= NULL;
01337    }
01338    return(1);
01339  }
01340  /* failed */
01341  isoburn_toc_destroy_arrays(o, 0);
01342  return(-1);
01343 }
01344 
01345 
01346 int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag)
01347 {
01348  if(o->sessions!=NULL)
01349    free((char *) o->sessions);
01350  o->sessions= NULL;
01351  if(o->session_pointers!=NULL)
01352    free((char *) o->session_pointers);
01353  o->session_pointers= NULL;
01354  if(o->tracks!=NULL)
01355    free((char *) o->tracks);
01356  o->tracks= NULL;
01357  if(o->track_pointers!=NULL)
01358    free((char *) o->track_pointers);
01359  o->track_pointers= NULL;
01360  return(1);
01361 }
01362 
01363 
01364 struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d)
01365 {
01366  int ret, session_count= 0, track_count= 0, num_tracks= 0, i, j;
01367  struct isoburn *o;
01368  struct isoburn_toc_entry *t;
01369  struct isoburn_toc_disc *toc_disc= NULL;
01370  struct burn_session **s;
01371  struct burn_track **tracks;
01372 
01373  toc_disc= calloc(1, sizeof(struct isoburn_toc_disc));
01374  if(toc_disc==NULL)
01375    return(NULL);
01376  toc_disc->disc= NULL;
01377  toc_disc->sessions= NULL;
01378  toc_disc->session_pointers= NULL;
01379  toc_disc->tracks= NULL;
01380  toc_disc->track_pointers= NULL;
01381  toc_disc->session_count= 0;
01382  toc_disc->track_count= 0;
01383  toc_disc->toc= NULL; 
01384 
01385  /* is the media emulated multi-session ? */
01386  ret= isoburn_find_emulator(&o, d, 0);
01387  if(ret<0)
01388    goto libburn;
01389  if(o->toc==NULL)
01390    goto libburn;
01391 
01392  /* This is an emulated TOC */
01393  toc_disc->toc= o->toc;
01394  for(t= toc_disc->toc; t!=NULL; t= t->next)
01395    session_count++;
01396  ret= isoburn_toc_new_arrays(toc_disc, session_count, session_count, 0);
01397  if(ret<=0)
01398    goto failure;
01399  t= toc_disc->toc;
01400  for(i= 0; i<session_count; i++) {
01401    toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+i;
01402    toc_disc->sessions[i].track_count= 1;
01403    toc_disc->sessions[i].toc_entry= t;
01404    toc_disc->session_pointers[i]= toc_disc->sessions+i;
01405    toc_disc->tracks[i].toc_entry= t;
01406    toc_disc->track_pointers[i]= toc_disc->tracks+i;
01407    t= t->next;
01408  }
01409  toc_disc->session_count= session_count;
01410  toc_disc->track_count= session_count;
01411  return(toc_disc);
01412 
01413 libburn:;
01414  /* This is a libburn provided TOC */
01415  toc_disc->disc= burn_drive_get_disc(d);
01416  if(toc_disc->disc == NULL) {
01417 failure:;
01418    free((char *) toc_disc);
01419    return(NULL);
01420  }
01421  s= burn_disc_get_sessions(toc_disc->disc, &session_count);
01422  for(i= 0; i<session_count; i++) {
01423    tracks = burn_session_get_tracks(s[i], &num_tracks);
01424    track_count+= num_tracks;
01425  }
01426  if(session_count<=0 || track_count<=0)
01427    goto failure;
01428  ret= isoburn_toc_new_arrays(toc_disc, session_count, track_count, 0);
01429  if(ret<=0)
01430    goto failure;
01431  track_count= 0;
01432  for(i= 0; i<session_count; i++) {
01433    tracks = burn_session_get_tracks(s[i], &num_tracks);
01434    toc_disc->sessions[i].session= s[i];
01435    toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+track_count;
01436    toc_disc->sessions[i].track_count= num_tracks;
01437    toc_disc->session_pointers[i]= toc_disc->sessions+i;
01438    for(j= 0; j<num_tracks; j++) {
01439      toc_disc->tracks[track_count+j].track= tracks[j];
01440      toc_disc->track_pointers[track_count+j]= toc_disc->tracks+(track_count+j);
01441    }
01442    track_count+= num_tracks;
01443  }
01444  toc_disc->session_count= session_count;
01445  toc_disc->track_count= track_count;
01446  return(toc_disc);
01447 }
01448 
01449 
01450 int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc)
01451 {
01452  struct isoburn_toc_entry *t;
01453  int ret= 0, num_sessions, num_tracks;
01454  struct burn_session **sessions;
01455  struct burn_track **tracks;
01456  struct burn_toc_entry entry;
01457 
01458  if(disc==NULL)
01459    return(0);
01460  if(disc->toc!=NULL) {
01461    for(t= disc->toc; t!=NULL; t= t->next)
01462      ret= t->start_lba + t->track_blocks;
01463  } else if(disc->disc!=NULL) {
01464    sessions= burn_disc_get_sessions(disc->disc, &num_sessions);
01465    if(num_sessions > 0) {
01466      tracks = burn_session_get_tracks(sessions[num_sessions - 1],
01467                                       &num_tracks);
01468      if(num_tracks > 0) {
01469        burn_track_get_entry(tracks[num_tracks - 1], &entry);
01470        if(entry.extensions_valid & 1)
01471          ret= entry.start_lba + entry.track_blocks;
01472      }
01473    }
01474 /*
01475    ret= burn_disc_get_sectors(disc->disc);
01476 */
01477  }
01478  return(ret);
01479 }
01480 
01481 
01482 struct isoburn_toc_session **isoburn_toc_disc_get_sessions(
01483                                       struct isoburn_toc_disc *disc, int *num)
01484 {
01485  *num= disc->session_count;
01486  return(disc->session_pointers);
01487 }
01488 
01489 
01490 int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s)
01491 {
01492  struct isoburn_toc_entry *t;
01493  int count= 0, i;
01494 
01495  if(s==NULL)
01496    return(0);
01497  if(s->toc_entry!=NULL) {
01498    t= s->toc_entry;
01499    for(i= 0; i<s->track_count; i++) {
01500      count+= t->track_blocks;
01501      t= t->next;
01502    }
01503  } else if(s->session!=NULL)
01504    count= burn_session_get_sectors(s->session);
01505  return(count);
01506 }
01507 
01508 
01509 int isoburn_toc_entry_finish(struct burn_toc_entry *entry,
01510                              int session_no, int track_no, int flag)
01511 {
01512  int pmin, psec, pframe;
01513 
01514  entry->extensions_valid= 1;
01515  entry->adr= 1;
01516  entry->control= 4;
01517  entry->session= session_no & 255;
01518  entry->session_msb= (session_no >> 8) & 255;
01519  entry->point= track_no & 255;
01520  entry->point_msb= (track_no >> 8) & 255;
01521 
01522  burn_lba_to_msf(entry->start_lba, &pmin, &psec, &pframe);
01523  if(pmin<=255)
01524    entry->pmin= pmin;
01525  else
01526    entry->pmin= 255;
01527  entry->psec= psec;
01528  entry->pframe= pframe; 
01529  return(1);
01530 }
01531 
01532 
01533 void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s,
01534                                        struct burn_toc_entry *entry)
01535 {
01536  struct isoburn_toc_track *t;
01537 
01538  if(s==NULL)
01539    return;
01540  if(s->session!=NULL && s->toc_entry==NULL) {
01541    burn_session_get_leadout_entry(s->session, entry);
01542    return;
01543  }
01544  if(s->track_count<=0 || s->track_pointers==NULL || s->toc_entry==NULL)
01545    return;
01546  t= s->track_pointers[s->track_count-1];
01547  entry->start_lba= t->toc_entry->start_lba + t->toc_entry->track_blocks;
01548  entry->track_blocks= 0;
01549  isoburn_toc_entry_finish(entry, s->toc_entry->session, t->toc_entry->track_no,
01550                           0);
01551 }
01552 
01553 
01554 struct isoburn_toc_track **isoburn_toc_session_get_tracks(
01555                                       struct isoburn_toc_session *s, int *num)
01556 {
01557  *num= s->track_count;
01558  return(s->track_pointers);
01559 }
01560 
01561 
01562 void isoburn_toc_track_get_entry(struct isoburn_toc_track *t,
01563                                  struct burn_toc_entry *entry)
01564 {
01565  if(t==0)
01566    return;
01567  if(t->track!=NULL && t->toc_entry==NULL) {
01568    burn_track_get_entry(t->track, entry);
01569    return;
01570  }
01571  if(t->toc_entry==NULL)
01572    return;
01573  entry->start_lba= t->toc_entry->start_lba;
01574  entry->track_blocks= t->toc_entry->track_blocks;
01575  isoburn_toc_entry_finish(entry, t->toc_entry->session, t->toc_entry->track_no,
01576                           0);
01577 }
01578 
01579 
01580 int isoburn_toc_track_get_emul(struct isoburn_toc_track *t, int *start_lba,
01581                                int *image_blocks, char volid[33], int flag)
01582 {
01583  if(t->toc_entry == NULL)
01584    return(0);
01585  if(t->toc_entry->volid == NULL)
01586    return(0);
01587  *start_lba= t->toc_entry->start_lba;
01588  *image_blocks= t->toc_entry->track_blocks;
01589  strncpy(volid, t->toc_entry->volid, 32);
01590  volid[32]= 0;
01591  return(1);
01592 }
01593 
01594 
01595 void isoburn_toc_disc_free(struct isoburn_toc_disc *d)
01596 {
01597  if(d->disc!=NULL)
01598    burn_disc_free(d->disc);
01599  isoburn_toc_destroy_arrays(d, 0);
01600  free((char *) d);
01601 }
01602 
01603 
01604 int isoburn_get_track_lba(struct isoburn_toc_track *track, int *lba, int flag)
01605 {
01606  struct burn_toc_entry entry;
01607 
01608  isoburn_toc_track_get_entry(track, &entry);
01609  if (entry.extensions_valid & 1)
01610    *lba= entry.start_lba;
01611  else
01612    *lba= burn_msf_to_lba(entry.pmin, entry.psec, entry.pframe);
01613  return(1);
01614 }
01615 
01616 
01617 int isoburn_drive_set_msgs_submit(struct burn_drive *d,
01618                             int (*msgs_submit)(void *handle, int error_code, 
01619                                                char msg_text[], int os_errno, 
01620                                                char severity[], int flag),
01621                             void *submit_handle, int submit_flag, int flag)
01622 {
01623  struct isoburn *o;
01624  int ret;
01625 
01626  ret= isoburn_find_emulator(&o, d, 0);
01627  if(ret<0 || o==NULL)
01628    return(-1);
01629  o->msgs_submit= msgs_submit;
01630  o->msgs_submit_handle= submit_handle;
01631  o->msgs_submit_flag= submit_flag;
01632  return(1);
01633 }
01634 
01635  
01636 /* @param flag bit0= with adr_mode 3: adr_value might be 16 blocks too high
01637                bit1= insist in seeing a disc object with at least one session
01638                bit2= with adr_mode 4: use adr_value as regular expression
01639 */
01640 int isoburn_set_msc1(struct burn_drive *d, int adr_mode, char *adr_value,
01641                      int flag)
01642 {
01643  int ret, num_sessions= 0, num_tracks, adr_num, i, j, total_tracks;
01644  int lba, best_lba, size, re_valid= 0, track_count= 0;
01645  time_t start_time= 0, last_pacifier= 0, now;
01646  char volid[33], msg[160];
01647  struct isoburn *o;
01648  struct isoburn_toc_disc *disc= NULL;
01649  struct isoburn_toc_session **sessions= NULL;
01650  struct isoburn_toc_track **tracks= NULL;
01651  static char mode_names[][20]= {"auto", "session", "track", "lba", "volid"};
01652  static int max_mode_names= 4;
01653  regex_t re;
01654  regmatch_t match[1];
01655 
01656  ret= isoburn_find_emulator(&o, d, 0);
01657  if(ret<0)
01658    return(-1);
01659  if(o==NULL)
01660    return(-1);
01661 
01662  start_time= last_pacifier= time(NULL);
01663  adr_num= atoi(adr_value);
01664  if(adr_mode!=3 || (flag & 2)) {
01665    disc= isoburn_toc_drive_get_disc(d);
01666    if(disc==NULL) {
01667 not_found:;
01668      if(adr_mode<0 || adr_mode>max_mode_names)
01669        goto unknown_mode;
01670      sprintf(msg, "Failed to find %s %s", mode_names[adr_mode],
01671                   strlen(adr_value)<=80 ?  adr_value : "-oversized-string-");
01672      isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
01673      ret= 0; goto ex;
01674    }
01675    sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
01676    if(sessions==NULL || num_sessions<=0)
01677      goto not_found;
01678  }
01679  if(adr_mode==0) {
01680    /* Set fabricated_msc1 to last session in TOC */
01681    tracks= isoburn_toc_session_get_tracks(sessions[num_sessions-1],
01682                                           &num_tracks);
01683    if(tracks==NULL || num_tracks<=0)
01684      goto not_found;
01685    isoburn_get_track_lba(tracks[0], &(o->fabricated_msc1), 0);
01686 
01687  } else if(adr_mode==1) {
01688    /* Use adr_num as session index (first session is 1, not 0) */
01689    if(adr_num<1 || adr_num>num_sessions)
01690      goto not_found;
01691    tracks= isoburn_toc_session_get_tracks(sessions[adr_num-1], &num_tracks);
01692    if(tracks==NULL || num_tracks<=0)
01693      goto not_found;
01694    isoburn_get_track_lba(tracks[0], &(o->fabricated_msc1), 0);
01695 
01696  } else if(adr_mode==2) {
01697    /* use adr_num as track index */
01698    total_tracks= 0;
01699    for(i=0; i<num_sessions; i++) {
01700      tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
01701      if(tracks==NULL)
01702    continue;
01703      for(j= 0; j<num_tracks; j++) {
01704        total_tracks++;
01705        if(total_tracks==adr_num) {
01706          isoburn_get_track_lba(tracks[j], &(o->fabricated_msc1), 0);
01707          ret= 1; goto ex;
01708        }
01709      }
01710    }
01711    goto not_found;
01712 
01713  } else if(adr_mode==3) {
01714    o->fabricated_msc1= adr_num;
01715    if((flag & 1) && o->fabricated_msc1 >= 16) {
01716      /* adr_num is possibly 16 blocks too high */
01717      ret= isoburn_read_iso_head(d, o->fabricated_msc1, &size,volid, 1|(1<<14));
01718      if(ret==2)
01719        o->fabricated_msc1-= 16;
01720    }
01721  } else if(adr_mode==4) {
01722    /* search for volume id that is equal to adr_value */
01723    if(flag & 4) {
01724      ret= regcomp(&re, adr_value, 0);
01725      if(ret != 0)
01726        flag&= ~4;
01727      else
01728        re_valid= 1;
01729    }
01730    best_lba= -1;
01731    for(i=0; i<num_sessions; i++) {
01732      tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
01733      if(tracks==NULL)
01734    continue;
01735      for(j= 0; j<num_tracks; j++) {
01736        now= time(NULL);
01737        if(now - last_pacifier >= 5 && track_count > 0) {
01738          last_pacifier= now;
01739          sprintf(msg,
01740                  "Scanned %d tracks for matching volid in %.f seconds",
01741                  track_count, (double) (now - start_time));
01742          isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
01743        }
01744        track_count++;
01745        ret= isoburn_toc_track_get_emul(tracks[0], &lba, &size, volid, 0);
01746        if(ret < 0)
01747      continue;
01748        if(ret == 0) {
01749          isoburn_get_track_lba(tracks[0], &lba, 0);
01750          ret= isoburn_read_iso_head(d, lba, &size, volid, 1);
01751          if(ret<=0)
01752      continue;
01753        }
01754        if(flag & 4) {
01755          ret= regexec(&re, volid, 1, match, 0);
01756          if(ret != 0)
01757      continue;
01758        } else {
01759          if(strcmp(volid, adr_value)!=0)
01760      continue;
01761        }
01762        best_lba= lba;
01763      }
01764    }
01765    if(best_lba<0)
01766      goto not_found;
01767    o->fabricated_msc1= best_lba;
01768 
01769  } else {
01770 unknown_mode:;
01771    sprintf(msg, "Program error: Unknown msc1 address mode %d", adr_mode);
01772    isoburn_msgs_submit(o, 0x00060000, msg, 0, "FATAL", 0);
01773    ret= 0; goto ex;
01774  }
01775  ret= 1;
01776 ex:;
01777  if(start_time != last_pacifier && track_count > 0) {
01778    now= time(NULL);
01779    sprintf(msg,
01780            "Scanned %d tracks for matching volid in %.f seconds",
01781            track_count, (double) (now - start_time));
01782    isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
01783  }
01784  if(disc!=NULL)
01785    isoburn_toc_disc_free(disc);
01786  if((flag & 4) && re_valid)
01787    regfree(&re);
01788  return(ret);
01789 }
01790 
01791 
01792 int isoburn_get_mount_params(struct burn_drive *d,
01793                              int adr_mode, char *adr_value,
01794                              int *lba, int *track, int *session,
01795                              char volid[33], int flag)
01796 {
01797  int msc1_mem, ret, total_tracks, num_sessions, num_tracks, i, j, track_lba;
01798  int size, is_iso= 0;
01799  struct isoburn *o;
01800  struct isoburn_toc_disc *disc= NULL;
01801  struct isoburn_toc_session **sessions= NULL;
01802  struct isoburn_toc_track **tracks= NULL;
01803 
01804  *lba= *track= *session= -1;
01805  volid[0]= 0;
01806  ret= isoburn_find_emulator(&o, d, 0);
01807  if(ret < 0 || o == NULL)
01808    return(-1);
01809  msc1_mem= o->fabricated_msc1;
01810  ret= isoburn_set_msc1(d, adr_mode, adr_value, 2 | (flag & 4));
01811  if(ret <= 0)
01812    return(ret);
01813  *lba= o->fabricated_msc1;
01814 
01815  disc= isoburn_toc_drive_get_disc(d);
01816  if(disc==NULL) 
01817    {ret= -1; goto ex;} /* cannot happen because checked by isoburn_set_msc1 */
01818  sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
01819  if(sessions==NULL || num_sessions<=0)
01820    {ret= -1; goto ex;} /* cannot happen because checked by isoburn_set_msc1 */
01821  total_tracks= 0;
01822  for(i=0; i<num_sessions && *session < 0; i++) {
01823    tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
01824    if(tracks==NULL)
01825  continue;
01826    for(j= 0; j<num_tracks && *track < 0; j++) {
01827      total_tracks++;
01828      isoburn_get_track_lba(tracks[j], &track_lba, 0);
01829      if(track_lba == *lba) {
01830        *track= total_tracks;
01831        *session= i + 1;
01832      }
01833    }
01834  }
01835  ret= isoburn_read_iso_head(d, *lba, &size, volid, 1);
01836  if(ret <= 0)
01837    volid[0]= 0;
01838  else
01839    is_iso= 1;
01840 
01841 ex:;
01842  o->fabricated_msc1= msc1_mem;
01843  return(2 - is_iso); 
01844 }
01845 
01846 

Generated on Tue Aug 17 2010 13:01:43 for libisoburn by  doxygen 1.7.1