1 
2 /*
3    cc -g -c \
4       -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
5       burn_wrap.c
6 */
7 /* libburn wrappers for libisoburn
8 
9    Copyright 2007 - 2017  Thomas Schmitt, <scdbackup@gmx.net>
10    Provided under GPL version 2 or later.
11 */
12 
13 #ifdef HAVE_CONFIG_H
14 #include "../config.h"
15 #endif
16 
17 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo
18 #define Hardcoded_cd_rW 1
19 #define Hardcoded_cd_rw_c1     12999
20 #define Hardcoded_cd_rw_nwA   152660
21 */
22 
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <regex.h>
33 
34 #ifndef Xorriso_standalonE
35 
36 #include <libburn/libburn.h>
37 #include <libisofs/libisofs.h>
38 #ifdef Xorriso_with_libjtE
39 #include <libjte/libjte.h>
40 #endif
41 
42 #else /* ! Xorriso_standalonE */
43 
44 #include "../libisofs/libisofs.h"
45 #include "../libburn/libburn.h"
46 #ifdef Xorriso_with_libjtE
47 #include "../libjte/libjte.h"
48 #endif
49 
50 #endif /* Xorriso_standalonE */
51 
52 
53 #include "libisoburn.h"
54 #include "isoburn.h"
55 
56 
57 /* The global list of isoburn objects. Usually there is only one. */
58 extern struct isoburn *isoburn_list_start; /* in isoburn.c */
59 
60 /* Default values for application provided msgs_submit methods.
61    To be attached to newly acquired drives.
62    Storage location is isoburn.c
63 */
64 extern int (*libisoburn_default_msgs_submit)
65     (void *handle, int error_code, char msg_text[],
66                  int os_errno, char severity[], int flag);
67 extern void *libisoburn_default_msgs_submit_handle;
68 extern int libisoburn_default_msgs_submit_flag;
69 
70 
71 static int isoburn_emulate_toc(struct burn_drive *d, int flag);
72 
73 
isoburn_initialize(char msg[1024],int flag)74 int isoburn_initialize(char msg[1024], int flag)
75 {
76  int major, minor, micro, bad_match= 0, no_iso_init= 0;
77 
78 
79 /* First the ugly compile time checks for header version compatibility.
80    If everything matches, then they produce no C code. In case of mismatch,
81    intentionally faulty C code will be inserted.
82 */
83 
84 #ifdef iso_lib_header_version_major
85 /* The minimum requirement of libisoburn towards the libisofs header
86    at compile time is defined in libisoburn/libisoburn.h :
87      isoburn_libisofs_req_major
88      isoburn_libisofs_req_minor
89      isoburn_libisofs_req_micro
90    It gets compared against the version macros in libisofs/libisofs.h :
91      iso_lib_header_version_major
92      iso_lib_header_version_minor
93      iso_lib_header_version_micro
94    If the header is too old then the following code shall cause failure of
95    libisoburn compilation rather than to allow production of a program with
96    unpredictable bugs or memory corruption.
97    The compiler messages supposed to appear in this case are:
98       error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function)
99       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)
100       error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function)
101 */
102 /* The indendation is an advise of man gcc to help old compilers ignoring */
103  #if isoburn_libisofs_req_major > iso_lib_header_version_major
104  #define Isoburn_libisofs_dot_h_too_olD 1
105  #endif
106  #if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor
107  #define Isoburn_libisofs_dot_h_too_olD 1
108  #endif
109  #if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro
110  #define Isoburn_libisofs_dot_h_too_olD 1
111  #endif
112 
113 #ifdef Isoburn_libisofs_dot_h_too_olD
114 LIBISOFS_MISCONFIGURATION = 0;
115 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_AND_burn_wrap_dot_c = 0;
116 LIBISOFS_MISCONFIGURATION_ = 0;
117 #endif
118 
119 #endif /* iso_lib_header_version_major */
120 
121 /* The minimum requirement of libisoburn towards the libburn header
122    at compile time is defined in libisoburn/libisoburn.h :
123      isoburn_libburn_req_major
124      isoburn_libburn_req_minor
125      isoburn_libburn_req_micro
126    It gets compared against the version macros in libburn/libburn.h :
127      burn_header_version_major
128      burn_header_version_minor
129      burn_header_version_micro
130    If the header is too old then the following code shall cause failure of
131    cdrskin compilation rather than to allow production of a program with
132    unpredictable bugs or memory corruption.
133    The compiler messages supposed to appear in this case are:
134       error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
135       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)
136       error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
137 */
138 
139 /* The indendation is an advise of man gcc to help old compilers ignoring */
140  #if isoburn_libburn_req_major > burn_header_version_major
141  #define Isoburn_libburn_dot_h_too_olD 1
142  #endif
143  #if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor
144  #define Isoburn_libburn_dot_h_too_olD 1
145  #endif
146  #if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro
147  #define Isoburn_libburn_dot_h_too_olD 1
148  #endif
149 
150 #ifdef Isoburn_libburn_dot_h_too_olD
151 LIBBURN_MISCONFIGURATION = 0;
152 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
153 LIBBURN_MISCONFIGURATION_ = 0;
154 #endif
155 
156 
157 #ifdef Xorriso_with_libjtE
158 
159 /* The minimum requirement of libisoburn towards the libjte header
160    at compile time is the same as the one of a usable libisofs towards libjte.
161    So the requirement is defined in libisofs/libisofs.h :
162      iso_libjte_req_major , iso_libjte_req_minor , iso_libjte_req_micro
163 */
164  /* The indendation is an advise of man gcc to help old compilers ignoring */
165  #if iso_libjte_req_major > LIBJTE_VERSION_MAJOR
166  #define Libisofs_libjte_dot_h_too_olD 1
167  #endif
168  #if iso_libjte_req_major == LIBJTE_VERSION_MAJOR && iso_libjte_req_minor > LIBJTE_VERSION_MINOR
169  #define Libisofs_libjte_dot_h_too_olD 1
170  #endif
171  #if iso_libjte_req_minor == LIBJTE_VERSION_MINOR && iso_libjte_req_micro > LIBJTE_VERSION_MICRO
172  #define Libisofs_libjte_dot_h_too_olD 1
173  #endif
174 
175 #ifdef Libisofs_libjte_dot_h_too_olD
176 LIBJTE_MISCONFIGURATION = 0;
177 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libjte_dot_h_TOO_OLD__SEE_libisofs_dot_h_AND_burn_wrap.c_c = 0;
178 LIBJTE_MISCONFIGURATION_ = 0;
179 #endif
180 
181 #endif /* Xorriso_with_libjtE */
182 
183 
184 /* End of ugly compile time tests (scroll up for explanation) */
185 
186 
187  msg[0]= 0;
188 
189 #ifdef Xorriso_with_libjtE
190 
191  libjte__version(&major, &minor, &micro);
192  sprintf(msg + strlen(msg), "libjte-%d.%d.%d ", major, minor, micro);
193  if (libjte__is_compatible(LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
194                                 LIBJTE_VERSION_MICRO, 0)) {
195    sprintf(msg+strlen(msg), "ok, ");
196  } else {
197    sprintf(msg + strlen(msg),
198            "- TOO OLD -, need at least libjte-%d.%d.%d ,\n",
199            LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
200            LIBJTE_VERSION_MICRO);
201    bad_match= 1;
202    no_iso_init= 1; /* iso_init() will fail anyway */
203  }
204 
205 #endif /* Xorriso_with_libjtE */
206 
207  if(!no_iso_init) {
208    if(iso_init()<0) {
209      sprintf(msg+strlen(msg), "Cannot initialize libisofs\n");
210      return(0);
211    }
212  }
213  iso_lib_version(&major, &minor, &micro);
214  sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro);
215 #ifdef iso_lib_header_version_major
216  if(iso_lib_is_compatible(iso_lib_header_version_major,
217                           iso_lib_header_version_minor,
218                           iso_lib_header_version_micro)) {
219    sprintf(msg+strlen(msg), "ok, ");
220  } else {
221    sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
222            iso_lib_header_version_major, iso_lib_header_version_minor,
223            iso_lib_header_version_micro);
224    bad_match= 1;
225  }
226 #else
227  if(iso_lib_is_compatible(isoburn_libisofs_req_major,
228                           isoburn_libisofs_req_minor,
229                           isoburn_libisofs_req_micro)) {
230    sprintf(msg+strlen(msg), "suspicious, ");
231  } else {
232    sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
233            isoburn_libisofs_req_major, isoburn_libisofs_req_minor,
234            isoburn_libisofs_req_micro);
235    bad_match= 1;
236  }
237 #endif /* ! iso_lib_header_version_major */
238 
239  if(!burn_initialize()) {
240    sprintf(msg+strlen(msg), "Cannot initialize libburn\n");
241    return(0);
242  }
243 
244  burn_version(&major, &minor, &micro);
245  sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro);
246  if(major > burn_header_version_major
247     || (major == burn_header_version_major
248         && (minor > burn_header_version_minor
249             || (minor == burn_header_version_minor
250                 && micro >= burn_header_version_micro)))) {
251    sprintf(msg+strlen(msg), "ok, ");
252  } else {
253    sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n",
254            burn_header_version_major, burn_header_version_minor,
255            burn_header_version_micro);
256    bad_match= 1;
257  }
258 
259  isoburn_version(&major, &minor, &micro);
260  sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro);
261  if(bad_match)
262    return(0);
263 
264  isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */
265  return(1);
266 }
267 
268 
269 /* API @since 0.1.0 */
isoburn_libisofs_req(int * major,int * minor,int * micro)270 int isoburn_libisofs_req(int *major, int *minor, int *micro)
271 {
272  *major= iso_lib_header_version_major;
273  *minor= iso_lib_header_version_minor;
274  *micro= iso_lib_header_version_micro;
275  return(1);
276 }
277 
278 
279 /* API @since 0.1.0 */
isoburn_libburn_req(int * major,int * minor,int * micro)280 int isoburn_libburn_req(int *major, int *minor, int *micro)
281 {
282  *major= burn_header_version_major;
283  *minor= burn_header_version_minor;
284  *micro= burn_header_version_micro;
285  return(1);
286 }
287 
288 
289 /* API @since 0.6.4 */
isoburn_libjte_req(int * major,int * minor,int * micro)290 int isoburn_libjte_req(int *major, int *minor, int *micro)
291 {
292 #ifdef Xorriso_with_libjtE
293  *major= LIBJTE_VERSION_MAJOR;
294  *minor= LIBJTE_VERSION_MINOR;
295  *micro= LIBJTE_VERSION_MICRO;
296 #else
297  *major= *minor= *micro= 0;
298 #endif /* ! Xorriso_with_libjtE */
299  return(1);
300 }
301 
302 
isoburn_set_msgs_submit(int (* msgs_submit)(void * handle,int error_code,char msg_text[],int os_errno,char severity[],int flag),void * submit_handle,int submit_flag,int flag)303 int isoburn_set_msgs_submit(int (*msgs_submit)(void *handle, int error_code,
304                                                char msg_text[], int os_errno,
305                                                char severity[], int flag),
306                                void *submit_handle, int submit_flag, int flag)
307 {
308  libisoburn_default_msgs_submit= msgs_submit;
309  libisoburn_default_msgs_submit_handle= submit_handle;
310  libisoburn_default_msgs_submit_flag= submit_flag;
311  return(1);
312 }
313 
314 
isoburn_is_intermediate_dvd_rw(struct burn_drive * d,int flag)315 int isoburn_is_intermediate_dvd_rw(struct burn_drive *d, int flag)
316 {
317  int profile, ret= 0, format_status, num_formats;
318  char profile_name[80];
319  enum burn_disc_status s;
320  off_t format_size= -1;
321  unsigned bl_sas;
322 
323  s= isoburn_disc_get_status(d);
324  ret= burn_disc_get_profile(d, &profile, profile_name);
325  if(ret>0 && profile==0x13)
326    ret= burn_disc_get_formats(d, &format_status, &format_size,
327                               &bl_sas, &num_formats);
328  if(ret>0 && profile==0x13 && s==BURN_DISC_BLANK &&
329     format_status==BURN_FORMAT_IS_UNKNOWN)
330    return(1);
331  return(0);
332 }
333 
334 
335 /** Examines the medium and sets appropriate emulation if needed.
336     @param flag bit0= pretent blank on overwriteable media
337                 bit3= if the drive reports a -ROM profile then try to read
338                       table of content by scanning for ISO image headers.
339                 bit4= do not emulate TOC on overwriteable media
340                 bit5= ignore ACL from external filesystems
341                 bit6= ignore POSIX Extended Attributes from external filesystems
342                 bit7= pretend -ROM and scan for table of content
343                 bit9= when scanning for ISO 9660 sessions on overwritable
344                       media: Do not demand a valid superblock at LBA 0
345                       and scan until end of medium.
346                bit10= if not bit6: accept all xattr namespaces from external
347                                    filesystems, not only "user.".
348 */
isoburn_welcome_media(struct isoburn ** o,struct burn_drive * d,int flag)349 static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
350                                  int flag)
351 {
352  int ret, profile, readonly= 0, role, random_access;
353  int emulation_started= 0;
354  struct burn_multi_caps *caps= NULL;
355  struct isoburn_toc_entry *t;
356  char profile_name[80];
357  struct isoburn_toc_disc *disc= NULL;
358  struct isoburn_toc_session **sessions;
359  struct isoburn_toc_track **tracks;
360  int num_sessions= 0, num_tracks= 0, track_count= 0, session_no= 0;
361  char msg[80];
362  enum burn_disc_status s;
363 
364 #ifndef Hardcoded_cd_rW
365  int lba, nwa;
366 #endif
367 
368  s= burn_disc_get_status(d);
369  profile_name[0]= 0;
370  ret= burn_disc_get_profile(d, &profile, profile_name);
371  if(ret<=0)
372    profile= 0x00;
373  ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0);
374  if(ret<0) /*== 0 is read-only medium, but it is too early to reject it here */
375    goto ex;
376  if(ret==0 || (flag & 128))
377    readonly= 1;
378  if(flag & 128)
379    flag = (flag & ~ 16) | 8;
380 
381  ret= isoburn_find_emulator(o, d, 0);
382  if(ret >= 0 && *o != NULL)
383    isoburn_destroy(o, 0);
384  ret= isoburn_new(o, 0);
385  if(ret<=0)
386    goto ex;
387  (*o)->drive= d;
388  (*o)->msgs_submit= libisoburn_default_msgs_submit;
389  (*o)->msgs_submit_handle= libisoburn_default_msgs_submit_handle;
390  (*o)->msgs_submit_flag= libisoburn_default_msgs_submit_flag;
391  iso_image_set_ignore_aclea((*o)->image,
392                             ((flag >> 5 ) & 3) | ((!!(flag & 1024)) << 3));
393 
394 #ifdef Hardcoded_cd_rW
395  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
396  caps->start_adr= 0;
397  (*o)->fabricated_disc_status= BURN_DISC_APPENDABLE;
398 #endif
399 
400  role= burn_drive_get_drive_role(d);
401  random_access= caps->start_adr || role == 4;
402  if(random_access)
403    (*o)->emulation_mode= 1;
404  if(random_access && !readonly) {       /* set emulation to overwriteable */
405    ret= isoburn_is_intermediate_dvd_rw(d, 0);
406    if(ret>0) {
407      (*o)->min_start_byte= 0;
408      (*o)->nwa= 0;
409      (*o)->zero_nwa= 0;
410    }
411    if((flag & 1) && role != 4 && role != 5) {
412      (*o)->nwa= (*o)->zero_nwa;
413      (*o)->fabricated_disc_status= BURN_DISC_BLANK;
414    } else {
415      ret= isoburn_start_emulation(*o, 0);
416      if(ret<=0) {
417        (*o)->emulation_mode= -1;
418        goto ex;
419      }
420      emulation_started= 1;
421      /* try to read emulated toc */
422      ret= isoburn_emulate_toc(d, (flag & 16) | ((!!(flag & 512)) << 1));
423      if(ret<0) {
424        (*o)->emulation_mode= -1;
425        goto ex;
426      }
427    }
428  } else {
429 
430     /* >>> recognize unsuitable media (but allow read-only media) */;
431 
432    if(readonly && s != BURN_DISC_EMPTY) {
433 
434      /* >>> ts B10712: This maps BURN_DISC_UNSUITABLE to BURN_DISC_FULL
435                        which can hardly be correct in general.
436         ??? What reason does this have ?
437      */
438      (*o)->fabricated_disc_status= BURN_DISC_FULL;
439 
440      /* This might be an overwriteable medium in a -ROM drive.
441         Pitfall:
442         Multi-session media which bear a xorriso image for overwriteables
443         in their first session would get a TOC of that first image rather
444         than of the medium.
445         It is not possible to distinguish a BD-RE from a single session
446         BD-R with an image for overwriteables. But as soon as the medium
447         bears 2 logical tracks it cannot be overwriteable.
448         So count the number of tracks first.
449      */
450      disc= isoburn_toc_drive_get_disc(d);
451      if(disc != NULL) {
452        sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
453        for(session_no= 0; session_no < num_sessions; session_no++) {
454          tracks= isoburn_toc_session_get_tracks(sessions[session_no],
455                                                 &num_tracks);
456          if(tracks != NULL)
457            track_count+= num_tracks;
458        }
459        isoburn_toc_disc_free(disc);
460      }
461 
462      sprintf(msg, "ROM medium has libburn track count = %d", track_count);
463      isoburn_msgs_submit(*o, 0x00060000, msg, 0, "DEBUG", 0);
464 
465      if((flag & 16) || track_count >= 2) {
466        ret= 0; /* toc emulation off, or not overwriteable */
467      } else {
468        ret= isoburn_start_emulation(*o, 1);
469        if(ret<=0) {
470          (*o)->emulation_mode= -1;
471          goto ex;
472        }
473        emulation_started= 1;
474        ret= isoburn_emulate_toc(d, 1 | ((!!(flag & 512)) << 1));
475        if(ret<0)
476          goto ex;
477        else if(ret > 0)
478          (*o)->emulation_mode= 1;
479      }
480      if(ret == 0 && (profile != 0x08 || (flag & 128)) && (flag & 8)) {
481        /* This might also be multi-session media which do not
482           get shown with a decent TOC.
483           CD-R TOC (profile 0x08) can be trusted. Others not.
484           Do a scan search of ISO headers.
485        */
486        if(!emulation_started) {
487          ret= isoburn_start_emulation(*o, 1);
488          if(ret<=0) {
489            (*o)->emulation_mode= -1;
490            goto ex;
491          }
492        }
493        ret= isoburn_emulate_toc(d, 1 | 2);
494        if(ret<0)
495          goto ex;
496        if(ret>0) { /* point msc1 to last session */
497          if((*o)->toc!=NULL) {
498            for(t= (*o)->toc; t->next!=NULL; t= t->next)
499              ; /* clang wants newline in empty loops */
500            (*o)->fabricated_msc1= t->start_lba;
501          }
502        }
503      }
504    }
505 #ifdef Hardcoded_cd_rW
506    (*o)->nwa= Hardcoded_cd_rw_nwA;
507 #else
508    ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
509    if(ret>0)
510      (*o)->nwa= nwa;
511    if((*o)->nwa < (*o)->zero_nwa)
512      (*o)->zero_nwa= 0;
513 #endif
514 
515  }
516 
517  ret= 1;
518 ex:
519  if(caps!=NULL)
520    burn_disc_free_multi_caps(&caps);
521  return(ret);
522 }
523 
524 
525 /**
526     @param flag bit0= load
527                 bit1= regard overwriteable media as blank
528                 bit2= if the drive is a regular disk file: truncate it to
529                       the write start address
530                 bit3= if the drive reports a -ROM profile then try to read
531                       table of content by scanning for ISO image headers.
532                       (depending on media type and drive state this might
533                        help or it might make the resulting toc even worse)
534                 bit4= do not emulate TOC on overwriteable media
535                 bit5= ignore ACL from external filesystems
536                 bit6= ignore POSIX Extended Attributes from external filesystems
537                 bit7= pretend -ROM profile and scan for table of content
538                 bit8= re-assess (*drive_infos)[0] rather than acquiring adr
539                 bit9= when scanning for ISO 9660 sessions on overwritable
540                       media: Do not demand a valid superblock at LBA 0
541                       and scan until end of medium.
542                bit10= if not bit6: accept all xattr namespaces from external
543                                    filesystems, not only "user.".
544 */
isoburn_drive_aquire(struct burn_drive_info * drive_infos[],char * adr,int flag)545 int isoburn_drive_aquire(struct burn_drive_info *drive_infos[],
546                          char *adr, int flag)
547 {
548  int ret, drive_grabbed= 0;
549  struct isoburn *o= NULL;
550  int conv_ret;
551  char *libburn_drive_adr= NULL;
552 
553  /* Should be obsolete by new drive addressing of libburn-0.5.2 */
554  /* but helps with kernel 2.4 to use /dev/sr */
555  libburn_drive_adr= calloc(1, BURN_DRIVE_ADR_LEN);
556  if(libburn_drive_adr == NULL)
557    {ret= -1; goto ex;}
558  conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr);
559  if(conv_ret<=0)
560    strcpy(libburn_drive_adr, adr);
561 
562  if(flag & 256)
563    ret= burn_drive_re_assess((*drive_infos)[0].drive, 0);
564  else
565    ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, flag&1);
566  if(ret<=0)
567    goto ex;
568  drive_grabbed= 1;
569  ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive,
570                             (flag & (8 | 16 | 32 | 64 | 128 | 512 | 1024)) |
571                             !!(flag&2));
572  if(ret<=0)
573    goto ex;
574 
575  if(flag&4) {
576    ret= isoburn_find_emulator(&o, (*drive_infos)[0].drive, 0);
577    if(ret>0 && o!=NULL)
578      o->truncate= 1;
579  }
580 
581  ret= 1;
582 ex:
583  if(ret<=0) {
584    if(drive_grabbed)
585      burn_drive_release((*drive_infos)[0].drive, 0);
586    isoburn_destroy(&o, 0);
587  }
588  if(libburn_drive_adr != NULL)
589    free(libburn_drive_adr);
590  return(ret);
591 }
592 
593 
isoburn_drive_scan_and_grab(struct burn_drive_info * drive_infos[],char * adr,int load)594 int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
595                                 char *adr, int load)
596 {
597  int ret;
598 
599  ret= isoburn_drive_aquire(drive_infos, adr, !!load);
600  return(ret);
601 }
602 
603 
isoburn_drive_grab(struct burn_drive * drive,int load)604 int isoburn_drive_grab(struct burn_drive *drive, int load)
605 {
606  int ret;
607  struct isoburn *o= NULL;
608 
609  ret= burn_drive_grab(drive, load);
610  if(ret<=0)
611    goto ex;
612  ret= isoburn_welcome_media(&o, drive, 0);
613  if(ret<=0)
614    goto ex;
615 
616  ret= 1;
617 ex:
618  if(ret<=0)
619    isoburn_destroy(&o,0);
620  return(ret);
621 }
622 
623 
624 /** Retrieve medium emulation and eventual isoburn emulator of drive.
625     @return -1 unsuitable medium, 0 generic medium, 1 emulated medium.
626 */
isoburn_find_emulator(struct isoburn ** pt,struct burn_drive * drive,int flag)627 int isoburn_find_emulator(struct isoburn **pt,
628                                  struct burn_drive *drive, int flag)
629 {
630  int ret;
631 
632  ret= isoburn_find_by_drive(pt, drive, 0);
633  if(ret<=0)
634    return(0);
635  if((*pt)->emulation_mode==-1) {
636    isoburn_msgs_submit(*pt, 0x00060000,
637                     "Unsuitable drive and medium state", 0, "FAILURE", 0);
638    return(-1);
639  }
640  if((*pt)->emulation_mode==0)
641    return(0);
642  return(1);
643 }
644 
645 
isoburn_disc_get_status(struct burn_drive * drive)646 enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive)
647 {
648  int ret;
649  struct isoburn *o;
650 
651  ret= isoburn_find_emulator(&o, drive, 0);
652  if(ret<0)
653    return(BURN_DISC_UNSUITABLE);
654  if(o!=NULL)
655    if(o->fabricated_disc_status!=BURN_DISC_UNREADY)
656      return(o->fabricated_disc_status);
657  if(ret==0)
658    return(burn_disc_get_status(drive));
659 
660  /* emulated status */
661  if(o->emulation_mode==-1)
662    return(BURN_DISC_UNSUITABLE);
663  if(o->nwa>o->zero_nwa)
664    return(BURN_DISC_APPENDABLE);
665  return(BURN_DISC_BLANK);
666 }
667 
668 
isoburn_disc_pretend_full_uncond(struct burn_drive * drive)669 int isoburn_disc_pretend_full_uncond(struct burn_drive *drive)
670 {
671  int ret;
672  struct isoburn *o;
673 
674  ret= isoburn_find_emulator(&o, drive, 0);
675  if(ret > 0 && o != NULL)
676    o->fabricated_disc_status= BURN_DISC_FULL;
677  ret= burn_disc_pretend_full_uncond(drive);
678  return(ret);
679 }
680 
681 
isoburn_disc_erasable(struct burn_drive * d)682 int isoburn_disc_erasable(struct burn_drive *d)
683 {
684  int ret;
685  struct isoburn *o;
686 
687  ret= isoburn_find_emulator(&o, d, 0);
688  if(ret>0)
689    if(o->emulation_mode==1)
690      return(1);
691  return burn_disc_erasable(d);
692 }
693 
694 
isoburn_is_overwritable(struct burn_drive * drive,int flag)695 static int isoburn_is_overwritable(struct burn_drive *drive, int flag)
696 {
697  char name[80];
698  int profile, ret;
699 
700  ret= burn_disc_get_profile(drive, &profile, name);
701  if(ret <= 0)
702    return(0);
703  if(profile == 0x12 || profile == 0x13 || profile == 0x1a || profile == 0x43)
704    return(1);
705  return(0);
706 
707 }
708 
709 
isoburn_disc_erase(struct burn_drive * drive,int fast)710 void isoburn_disc_erase(struct burn_drive *drive, int fast)
711 {
712  int ret, do_pseudo_blank= 0, role;
713  struct isoburn *o;
714  enum burn_disc_status s;
715  char *zero_buffer= NULL;
716  struct burn_multi_caps *caps= NULL;
717 
718  zero_buffer= calloc(1, Libisoburn_target_head_sizE);
719  if(zero_buffer == NULL) {
720    /* To cause a negative reply with burn_drive_wrote_well() */
721    burn_drive_cancel(drive);
722    goto ex;
723  }
724 
725  ret= isoburn_find_emulator(&o, drive, 0);
726  if(ret>0) {
727    if(o->emulation_mode==-1) {
728      /* To cause a negative reply with burn_drive_wrote_well() */
729      burn_drive_cancel(drive);
730      goto ex;
731    }
732    role = burn_drive_get_drive_role(drive);
733    if (role == 5) {
734      /* libburn will truncate the random-access write-only file
735         to zero size and change its state */
736      burn_disc_erase(drive, fast);
737      o->fabricated_disc_status= burn_disc_get_status(drive);
738      o->nwa= o->zero_nwa= 0;
739      goto ex;
740    }
741    if(o->emulation_mode > 0) { /* might be readonly with emulated sessions */
742      ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
743      if(ret <= 0) /* Maybe because of burn_disc_pretend_full() */
744        do_pseudo_blank= isoburn_is_overwritable(drive, 0); /* known profiles */
745      else if(caps->start_adr)
746        do_pseudo_blank= 1;
747    }
748    if(do_pseudo_blank) {
749      s= isoburn_disc_get_status(drive);
750      if(s==BURN_DISC_FULL) { /* unknown data format in first 64 kB */
751        memset(zero_buffer, 0, Libisoburn_target_head_sizE);
752        ret= burn_random_access_write(drive, (off_t) 0, zero_buffer,
753                                      (off_t) Libisoburn_target_head_sizE, 1);
754      } else {
755        ret= isoburn_invalidate_iso(o, 0);
756      }
757      if(ret<=0)
758        burn_drive_cancel(drive); /* mark run as failure */
759      goto ex;
760    }
761  }
762  burn_disc_erase(drive, fast);
763 ex:;
764  if(caps!=NULL)
765    burn_disc_free_multi_caps(&caps);
766  if(zero_buffer != NULL)
767    free(zero_buffer);
768 }
769 
770 
isoburn_disc_available_space(struct burn_drive * d,struct burn_write_opts * opts)771 off_t isoburn_disc_available_space(struct burn_drive *d,
772                                    struct burn_write_opts *opts)
773 {
774  int ret;
775  struct isoburn *o;
776  struct burn_write_opts *eff_opts= NULL, *local_opts= NULL;
777  enum burn_disc_status s;
778  off_t avail;
779 
780  eff_opts= opts;
781  ret= isoburn_find_emulator(&o, d, 0);
782  if(ret>0 && o!=NULL)
783    if(o->emulation_mode!=0) {
784      s= isoburn_disc_get_status(d);
785      if(s==BURN_DISC_FULL) /* unknown data format in first 64 kB */
786        return((off_t) 0);
787      local_opts= burn_write_opts_new(d);
788      eff_opts= local_opts;
789      burn_write_opts_set_start_byte(eff_opts, ((off_t) o->nwa) * (off_t) 2048);
790    }
791  avail= burn_disc_available_space(d, eff_opts);
792  if(local_opts!=NULL)
793    burn_write_opts_free(local_opts);
794  local_opts= NULL;
795  return(avail);
796 }
797 
798 
isoburn_disc_get_msc1(struct burn_drive * d,int * start_lba)799 int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba)
800 {
801  int ret;
802  struct isoburn *o;
803 
804 #ifdef Hardcoded_cd_rW
805  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
806  *start_lba= Hardcoded_cd_rw_c1;
807  return(1);
808 #endif
809 
810  if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE &&
811     isoburn_disc_get_status(d)!=BURN_DISC_FULL) {
812    isoburn_msgs_submit(NULL, 0x00060000,
813                        "Medium contains no recognizable data", 0, "SORRY", 0);
814    return(0);
815  }
816  ret= isoburn_find_emulator(&o, d, 0);
817  if(ret<0)
818    return(0);
819  if(o->fabricated_msc1>=0) {
820    *start_lba= o->fabricated_msc1;
821    return(1);
822  }
823  if(ret>0) if(o->emulation_mode>0) {
824    *start_lba= 0;
825    return(1);
826  }
827  return(burn_disc_get_msc1(d, start_lba));
828 }
829 
830 
isoburn_disc_track_lba_nwa(struct burn_drive * d,struct burn_write_opts * opts,int trackno,int * lba,int * nwa)831 int isoburn_disc_track_lba_nwa(struct burn_drive *d,
832                                struct burn_write_opts *opts,
833                                int trackno, int *lba, int *nwa)
834 {
835  int ret;
836  struct isoburn *o;
837  enum burn_disc_status s;
838 
839 #ifdef Hardcoded_cd_rW
840  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
841  *lba= Hardcoded_cd_rw_c1;
842  *nwa= Hardcoded_cd_rw_nwA;
843  return(1);
844 #endif
845 
846  *nwa= *lba= 0;
847  ret= isoburn_find_emulator(&o, d, 0);
848  if(ret<0)
849    return(0);
850  if(ret>0) if(o->emulation_mode>0) {
851    *lba= 0;
852    *nwa= o->nwa;
853    return(1);
854  }
855  if(burn_drive_get_drive_role(d) != 1)
856    return(1);
857 
858  s= isoburn_disc_get_status(d);
859  if(s == BURN_DISC_BLANK) /* We do not believe in anything but nwa = lba = 0 */
860    return(1);
861  return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa));
862 }
863 
864 
isoburn_get_msc2(struct isoburn * o,struct burn_write_opts * opts,int * msc2,int flag)865 int isoburn_get_msc2(struct isoburn *o,
866                      struct burn_write_opts *opts, int *msc2, int flag)
867 {
868  int ret, lba, nwa;
869 
870  if(o->fabricated_msc2>=0)
871    *msc2= o->fabricated_msc2;
872  else {
873    ret= isoburn_disc_track_lba_nwa(o->drive, opts, 0, &lba, &nwa);
874    if(ret<=0)
875      return(ret);
876    *msc2= nwa;
877  }
878  return(1);
879 }
880 
881 /* @param flag bit0= truncate (else do not truncate)
882                bit1= do not warn if call is inappropriate to drive
883                bit2= only set if truncation is currently enabled
884 */
isoburn_set_truncate(struct burn_drive * drive,int flag)885 int isoburn_set_truncate(struct burn_drive *drive, int flag)
886 {
887  int ret;
888  struct isoburn *o;
889 
890  ret= isoburn_find_emulator(&o, drive, 0);
891  if(ret < 0)
892    return ret;
893  if(o == NULL) {
894    if(!(flag & (2 | 4)))
895      isoburn_msgs_submit(o, 0x00060000,
896         "Drive type or role is inappropriate for truncation", 0, "WARNING", 0);
897    return(0);
898  }
899  if(o->truncate || !(flag & 4))
900    o->truncate= flag & 1;
901  return(1);
902 }
903 
904 
isoburn_disc_write(struct burn_write_opts * opts,struct burn_disc * disc)905 void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
906 {
907  int ret;
908  off_t nwa= 0;
909  struct isoburn *o;
910  struct burn_drive *drive;
911  char *reasons= NULL, *msg= NULL, *adr= NULL;
912  struct stat stbuf;
913  enum burn_write_types write_type;
914 
915  drive= burn_write_opts_get_drive(opts);
916 
917  reasons= calloc(1, BURN_REASONS_LEN);
918  msg= calloc(1, 160+BURN_REASONS_LEN);
919  adr= calloc(1, BURN_DRIVE_ADR_LEN);
920  if(reasons == NULL || msg == NULL || adr == NULL) {
921    /* To cause a negative reply with burn_drive_wrote_well() */
922    burn_drive_cancel(drive);
923    goto ex;
924  }
925 
926  ret= isoburn_find_emulator(&o, drive, 0);
927  if(ret<0)
928    goto ex;
929  if(o == NULL) {
930    sprintf(msg,
931           "Program error: Cannot find isoburn object associated to the drive");
932    isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
933    burn_drive_cancel(drive);
934    goto ex;
935  }
936  o->wrote_well= -1;
937  if(o->emulation_mode!=0) {
938    burn_write_opts_set_multi(opts, 0);
939    if(o->emulation_mode>0 && o->nwa >= 0) {
940      nwa= o->nwa;
941 
942      /* This caters for unwritten formatted DVD-RW. They need to be written
943         sequentially on the first use. Only written areas are random access.
944         If the first session is not written to LBA 0, then re-opening of
945         formatting and padding is needed.
946         This can be done. But when the track gets closed after padding,
947         this lasts a long time. There is a high risk that an app will not
948         poll the message queue while waiting for  isoburn_disc_write()  to
949         return. The pacifier loop usually happens only afterwards.
950         So automatic formatting might cause a nervous clueless user.
951      */
952      ret= isoburn_is_intermediate_dvd_rw(drive, 0);
953      if(ret>0 && nwa>0 && nwa <= o->zero_nwa) {
954        /* actually this should not happen since such media get recognized
955           by isoburn_welcome_media and o->zero_nwa gets set to 0
956        */
957        sprintf(msg,
958       "DVD-RW insufficiently formatted. (Intermediate State, size unknown)");
959        isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
960        sprintf(msg,
961               "It might help to first deformat it and then format it again");
962        isoburn_msgs_submit(o, 0x00060000, msg, 0, "HINT", 0);
963        burn_drive_cancel(drive); /* mark run as failure */
964        goto ex;
965      }
966      /* end of DVD-RW oriented check */
967      burn_write_opts_set_start_byte(opts, nwa * (off_t) 2048);
968    }
969  }
970 
971  if(o->do_tao) {
972    if (o->do_tao > 0)
973      burn_write_opts_set_write_type(opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
974    else
975      burn_write_opts_set_write_type(opts, BURN_WRITE_SAO, BURN_BLOCK_SAO);
976 
977    ret = burn_precheck_write(opts, disc, reasons, 0);
978    if(ret <= 0) {
979      sprintf(msg, "Cannot set write type %s for this medium.",
980              o->do_tao > 0 ? "TAO" : "SAO");
981      sprintf(msg + strlen(msg), "Reasons given:\n   %s", reasons);
982      goto no_write_type;
983    }
984    sprintf(msg, "Explicitly chosen write type: %s",
985            o->do_tao > 0 ? "TAO" : "SAO");
986    isoburn_msgs_submit(o, 0x00060000, msg, 0, "NOTE", 0);
987  } else {
988    write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
989    if (write_type == BURN_WRITE_NONE) {
990       sprintf(msg, "Failed to find a suitable write type:\n%s", reasons);
991 no_write_type:;
992       isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
993       if(o!=NULL)
994         o->wrote_well= 0;
995       /* To cause a negative reply with burn_drive_wrote_well() */
996       burn_drive_cancel(drive);
997       goto ex;
998    }
999 
1000    sprintf(reasons, "%d", (int) write_type);
1001    sprintf(msg, "Write_type = %s\n",
1002                 (write_type == BURN_WRITE_SAO ? "SAO" :
1003                 (write_type == BURN_WRITE_TAO ? "TAO" : reasons)));
1004    isoburn_msgs_submit(o, 0x00060000, msg, 0, "DEBUG", 0);
1005  }
1006 
1007 #ifdef Hardcoded_cd_rW
1008  /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
1009  fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA);
1010  burn_write_opts_set_start_byte(opts,
1011 				 ((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048);
1012 #endif
1013 
1014  if(o->truncate) {
1015    ret= burn_drive_get_drive_role(drive);
1016    if(ret == 2 || ret == 5) {
1017      ret= burn_drive_d_get_adr(drive, adr);
1018      if(ret>0) {
1019        ret= lstat(adr, &stbuf);
1020        if(ret!=-1)
1021          if(S_ISREG(stbuf.st_mode))
1022            ret= truncate(adr, nwa * (off_t) 2048);
1023            /* (result of truncate intentionally ignored) */
1024      }
1025    }
1026  }
1027 
1028  burn_disc_write(opts, disc);
1029 ex:;
1030  if(reasons != NULL)
1031    free(reasons);
1032  if(msg != NULL)
1033    free(msg);
1034  if(adr != NULL)
1035    free(adr);
1036 }
1037 
1038 
isoburn_drive_release(struct burn_drive * drive,int eject)1039 void isoburn_drive_release(struct burn_drive *drive, int eject)
1040 {
1041  int ret;
1042  struct isoburn *o;
1043 
1044  ret= isoburn_find_emulator(&o, drive, 0);
1045  if(ret<0)
1046    return;
1047  if(o!=NULL) {
1048    isoburn_destroy(&o, 0);
1049  }
1050  burn_drive_release(drive, eject);
1051 }
1052 
1053 
isoburn_finish(void)1054 void isoburn_finish(void)
1055 {
1056  isoburn_destroy_all(&isoburn_list_start, 0);
1057  burn_finish();
1058  iso_finish();
1059 }
1060 
1061 
isoburn_needs_emulation(struct burn_drive * drive)1062 int isoburn_needs_emulation(struct burn_drive *drive)
1063 {
1064  int ret;
1065  struct isoburn *o;
1066  enum burn_disc_status s;
1067 
1068  s= isoburn_disc_get_status(drive);
1069  if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE)
1070    return(-1);
1071  ret= isoburn_find_emulator(&o, drive, 0);
1072  if(ret<0)
1073    return(-1);
1074  if(ret>0)
1075    if(o->emulation_mode>0)
1076      return(1);
1077  return(0);
1078 }
1079 
1080 
isoburn_set_start_byte(struct isoburn * o,off_t value,int flag)1081 int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag)
1082 {
1083  int ret;
1084  struct burn_drive *drive = o->drive;
1085  struct burn_multi_caps *caps= NULL;
1086 
1087  ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
1088  if(ret<=0)
1089    goto ex;
1090  if(!caps->start_adr) {
1091    isoburn_msgs_submit(o, 0x00060000,
1092                        "Cannot set start byte address with this type of media",
1093                        0, "FAILURE", 0);
1094    {ret= 0; goto ex;}
1095  }
1096  o->min_start_byte= value;
1097  if(value % caps->start_alignment)
1098    value+= caps->start_alignment - (value % caps->start_alignment);
1099  o->nwa= value/2048;
1100  if(o->nwa < o->zero_nwa)
1101    o->zero_nwa= 0;
1102  /* If suitable for media alignment, round up to Libisoburn_nwa_alignemenT */
1103  if((o->nwa % Libisoburn_nwa_alignemenT) &&
1104      ((Libisoburn_nwa_alignemenT*2048) % caps->start_alignment)==0 )
1105    o->nwa+= Libisoburn_nwa_alignemenT - (o->nwa % Libisoburn_nwa_alignemenT);
1106  ret= 1;
1107 ex:
1108  if(caps!=NULL)
1109    burn_disc_free_multi_caps(&caps);
1110  return(ret);
1111 }
1112 
1113 
isoburn_get_min_start_byte(struct burn_drive * d,off_t * start_byte,int flag)1114 int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
1115                                int flag)
1116 {
1117  int ret;
1118  struct isoburn *o;
1119 
1120  ret= isoburn_find_emulator(&o, d, 0);
1121  if(ret<0)
1122    return(-1);
1123  if(ret==0)
1124    return(0);
1125  *start_byte= o->min_start_byte;
1126  if(o->min_start_byte<=0)
1127    return(0);
1128  return(1);
1129 }
1130 
1131 
isoburn_drive_wrote_well(struct burn_drive * d)1132 int isoburn_drive_wrote_well(struct burn_drive *d)
1133 {
1134  int ret;
1135  struct isoburn *o;
1136 
1137  ret= isoburn_find_emulator(&o, d, 0);
1138  if(ret<0)
1139    return(-1);
1140  if(o!=NULL)
1141    if(o->wrote_well>=0)
1142      return(o->wrote_well);
1143  ret= burn_drive_wrote_well(d);
1144  return ret;
1145 }
1146 
1147 
isoburn_get_fifo_status(struct burn_drive * d,int * size,int * free_bytes,char ** status_text)1148 int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
1149 			    char **status_text)
1150 {
1151  int ret;
1152  struct isoburn *o;
1153  size_t hsize= 0, hfree_bytes= 0;
1154 
1155  ret= isoburn_find_emulator(&o, d, 0);
1156  if(ret<0)
1157    return(-1);
1158 
1159  if(o==NULL)
1160    return(-1);
1161  if(o->iso_source==NULL)
1162    return(-1);
1163  ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes);
1164  if(hsize > 1024*1024*1024)
1165    *size= 1024*1024*1024;
1166  else
1167    *size= hsize;
1168  if(hfree_bytes > 1024*1024*1024)
1169    *free_bytes= 1024*1024*1024;
1170  else
1171    *free_bytes= hfree_bytes;
1172  *status_text= "";
1173  if(ret==0)
1174    *status_text= "standby";
1175  else if(ret==1)
1176    *status_text= "active";
1177  else if(ret==2)
1178    *status_text= "ending";
1179  else if(ret==3)
1180    *status_text= "failing";
1181  else if(ret==4)
1182    *status_text= "unused";
1183  else if(ret==5)
1184    *status_text= "abandoned";
1185  else if(ret==6)
1186    *status_text= "ended";
1187  else if(ret==7)
1188    *status_text= "aborted";
1189  return(ret);
1190 }
1191 
1192 
1193 /* @param flag bit0= -reserved-
1194                bit1= this is a libburn severity
1195 */
isoburn__sev_to_text(int severity,char ** severity_name,int flag)1196 int isoburn__sev_to_text(int severity, char **severity_name,
1197                          int flag)
1198 {
1199  int ret;
1200 
1201  ret= iso_sev_to_text(severity, severity_name);
1202  if(ret>0)
1203    return(ret);
1204  ret= burn_sev_to_text(severity, severity_name, 0);
1205  return(ret);
1206 }
1207 
1208 
isoburn__text_to_sev(char * severity_name,int * severity_number,int flag)1209 int isoburn__text_to_sev(char *severity_name, int *severity_number, int flag)
1210 {
1211  int ret= 1;
1212 
1213  ret= iso_text_to_sev(severity_name, severity_number);
1214  if(ret>0)
1215    return(ret);
1216  ret= burn_text_to_sev(severity_name, severity_number, 0);
1217  return(ret);
1218 }
1219 
1220 
isoburn_report_iso_error(int iso_error_code,char msg_text[],int os_errno,char min_severity[],int flag)1221 int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
1222                              char min_severity[], int flag)
1223 {
1224  int error_code, iso_sev, min_sev, ret;
1225  char *sev_text_pt, *msg_text_pt= NULL;
1226 
1227  error_code= iso_error_get_code(iso_error_code);
1228  if(error_code < 0x00030000 || error_code >= 0x00040000)
1229    error_code= (error_code & 0xffff) | 0x00050000;
1230 
1231  if(iso_error_code<0)
1232    msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
1233  if(msg_text_pt==NULL)
1234    msg_text_pt= msg_text;
1235  iso_sev= iso_error_get_severity(iso_error_code);
1236  sev_text_pt= min_severity;
1237  isoburn__text_to_sev(min_severity, &min_sev, 0);
1238  if(min_sev < iso_sev)
1239    isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
1240  ret= iso_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, 0);
1241  return(ret);
1242 }
1243 
1244 
1245 /* @param flag bit0-7: info return mode
1246                  0= do not return anything in info (do not even touch it)
1247                  1= copy volume id to info (info needs 33 bytes)
1248                  2= do not touch info (caller will copy 64 kB header to it)
1249                bit14= -reserved -
1250                bit15= -reserved-
1251    @return 1 seems to be a valid ISO image , 0 format not recognized, <0 error
1252 */
isoburn_read_iso_head_parse(unsigned char * data,int * image_blocks,char * info,int flag)1253 int isoburn_read_iso_head_parse(unsigned char *data,
1254                                 int *image_blocks, char *info, int flag)
1255 {
1256  int i, info_mode;
1257 
1258  /* is this an ISO image ? */
1259  if(data[0]!=1)
1260    return(0);
1261  if(strncmp((char *) (data+1),"CD001",5)!=0)
1262    return(0);
1263  /* believe so */
1264 
1265  *image_blocks= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24);
1266  info_mode= flag&255;
1267  if(info_mode==0) {
1268    ;
1269  } else if(info_mode==1) {
1270    strncpy(info, (char *) (data+40), 32);
1271    info[32]= 0;
1272    for(i= strlen(info)-1; i>=0; i--)
1273      if(info[i]!=' ')
1274    break;
1275      else
1276        info[i]= 0;
1277  } else if(info_mode==2) {
1278    ;
1279  } else {
1280    isoburn_msgs_submit(NULL, 0x00060000,
1281                "Program error: Unknown info mode with isoburn_read_iso_head()",
1282                0, "FATAL", 0);
1283    return(-1);
1284  }
1285  return(1);
1286 }
1287 
1288 
1289 /* API
1290    @param flag bit0-7: info return mode
1291                  0= do not return anything in info (do not even touch it)
1292                  1= copy volume id to info (info needs 33 bytes)
1293                  2= copy 64 kB header to info (needs 65536 bytes)
1294                bit13= do not read head from media but use first 64 kB from info
1295                bit14= check both half buffers (not only second)
1296                       return 2 if found in first block
1297                bit15= return-1 on read error
1298    @return 1 seems to be a valid ISO image , 2 found in first half buffer,
1299            0 format not recognized, <0 error
1300 */
isoburn_read_iso_head(struct burn_drive * d,int lba,int * image_blocks,char * info,int flag)1301 int isoburn_read_iso_head(struct burn_drive *d, int lba,
1302                           int *image_blocks, char *info, int flag)
1303 {
1304  unsigned char *buffer= NULL;
1305  int ret, info_mode, capacity, role;
1306  off_t data_count, to_read;
1307  struct isoburn *o;
1308 
1309  buffer= calloc(1, 64 * 1024);
1310  if(buffer == NULL)
1311    {ret= -1; goto ex;}
1312 
1313  info_mode= flag&255;
1314  *image_blocks= 0;
1315  if(flag&(1<<13)) {
1316    memcpy(buffer, info, 64*1024);
1317  } else {
1318    memset(buffer, 0, 64 * 1024);
1319    role = burn_drive_get_drive_role(d);
1320    if (role == 3 || role == 5)
1321 
1322      /* >>> ??? return always 0 ? */
1323      {ret= (-1*!!(flag&(1<<15))); goto ex;}
1324 
1325    ret = burn_get_read_capacity(d, &capacity, 0);
1326    if (ret <= 0 && (role == 2 || role == 4)) {
1327      /* Might be a block device on a system where libburn cannot determine its
1328         size.  Try to read anyway. */
1329      capacity = 0x7ffffff0;
1330      ret = 1;
1331    }
1332    to_read= (off_t) capacity * ((off_t) 2048);
1333    if(ret > 0 && to_read >= (off_t) (36 * 1024)) {
1334      ret= isoburn_find_emulator(&o, d, 0);
1335      if(ret > 0)
1336        if(o->media_read_error)
1337          {ret= (-1 * !!(flag & (1 << 15))); goto ex;}
1338      if(to_read >= (off_t) (64 * 1024))
1339        to_read= 64 * 1024;
1340      ret = burn_read_data(d, ((off_t) lba) * (off_t) 2048, (char *) buffer,
1341                       to_read, &data_count, 32); /* error messages as DEBUG */
1342    } else
1343      ret= 0;
1344    if(ret<=0)
1345      {ret= (-1*!!(flag&(1<<15))); goto ex;}
1346    if(info_mode==2)
1347      memcpy(info, buffer, 64*1024);
1348  }
1349 
1350  if(flag&(1<<14)) {
1351    ret= isoburn_read_iso_head_parse(buffer, image_blocks, info, info_mode);
1352    if(ret<0)
1353      goto ex;
1354    if(ret>0)
1355      {ret= 2; goto ex;}
1356  }
1357  ret= isoburn_read_iso_head_parse(buffer+32*1024, image_blocks, info,
1358                                   info_mode);
1359  if(ret<=0)
1360    goto ex;
1361  ret= 1;
1362 ex:;
1363  if(buffer != NULL)
1364    free(buffer);
1365  return(ret);
1366 }
1367 
1368 
isoburn_make_toc_entry(struct isoburn * o,int * session_count,int lba,int track_blocks,char * volid,int flag)1369 int isoburn_make_toc_entry(struct isoburn *o, int *session_count, int lba,
1370                            int track_blocks, char *volid, int flag)
1371 {
1372  int ret;
1373  struct isoburn_toc_entry *item;
1374 
1375  ret= isoburn_toc_entry_new(&item, o->toc, 0);
1376  if(ret<=0) {
1377 no_memory:;
1378    isoburn_msgs_submit(o, 0x00060000,
1379                        "Not enough memory for emulated TOC entry object",
1380                        0, "FATAL", 0);
1381    return(-1);
1382  }
1383  if(o->toc==NULL)
1384    o->toc= item;
1385  (*session_count)++;
1386  item->session= *session_count;
1387  item->track_no= *session_count;
1388  item->start_lba= lba;
1389  item->track_blocks= track_blocks;
1390  if(volid != NULL) {
1391    item->volid= strdup(volid);
1392    if(item->volid == NULL)
1393      goto no_memory;
1394  }
1395  return(1);
1396 }
1397 
1398 
1399 /* @param flag bit0= allow unemulated media
1400                bit1= free scanning without enclosing LBA-0-header
1401                bit4= represent emulated media as one single session
1402                      (not with bit1)
1403    @return -1 severe error, 0= no neat header chain, 1= credible chain read
1404 */
isoburn_emulate_toc(struct burn_drive * d,int flag)1405 int isoburn_emulate_toc(struct burn_drive *d, int flag)
1406 {
1407  int ret, image_size= 0, lba, track_blocks, session_count= 0, read_flag= 0;
1408  int scan_start= 0, scan_count= 0, probe_minus_16= 0, growisofs_nwa, role;
1409  int with_enclosure= 0, readable_blocks= -1;
1410  struct isoburn *o;
1411  char *msg= NULL, *size_text= NULL, *sev, volid[33], *volid_pt= NULL;
1412  time_t start_time, last_pacifier, now;
1413 
1414  msg= calloc(1, 160);
1415  size_text= calloc(1, 80);
1416  if(msg == NULL || size_text == NULL)
1417    {ret= -1; goto ex;}
1418 
1419  /* is the medium emulated multi-session ? */
1420  ret= isoburn_find_emulator(&o, d, 0);
1421  if(ret<0)
1422    {ret= -1; goto ex;}
1423  if(o==NULL)
1424    {ret= -1; goto ex;}
1425  if(o->emulation_mode<=0 && !(flag&1))
1426    {ret= 0; goto ex;}
1427 
1428  ret= burn_get_read_capacity(d, &readable_blocks, 0);
1429  if(ret <= 0) {
1430    role = burn_drive_get_drive_role(d);
1431    if (role == 2 || role == 4)
1432      /* Might be a block device on a system where libburn cannot determine its
1433         size.  Try to read anyway. */
1434      readable_blocks= 0x7ffffff0; /* try to read anyway */
1435    else
1436      readable_blocks= -1;
1437  }
1438  if(o->fabricated_disc_status == BURN_DISC_BLANK)
1439    {ret= 0; goto failure;}
1440 
1441  start_time= last_pacifier= time(NULL);
1442  lba= 0;
1443  if(flag & 2) {
1444    /* If there is a PVD at LBA 32 then this is an image with emulated TOC */
1445    ret= isoburn_read_iso_head(d, 32, &image_size, NULL, 0);
1446    if(ret > 0)
1447      lba= 32;
1448  } else {
1449    ret= isoburn_read_iso_head(d, lba, &image_size, NULL, 0);
1450    if(ret<=0)
1451      {ret= 0; goto failure;}
1452    lba= o->target_iso_head_size / 2048;
1453    with_enclosure= 1;
1454    if((flag & 16) && o->emulation_mode == 1) {
1455      ret= 1;
1456      goto failure; /* This will represent the medium as single session */
1457    }
1458  }
1459  while(lba<image_size || (flag&2)) {
1460    now= time(NULL);
1461    if(now - last_pacifier >= 5) {
1462      last_pacifier= now;
1463      if(scan_count>=10*512)
1464        sprintf(size_text, "%.f MB", ((double) scan_count) / 512.0);
1465      else
1466        sprintf(size_text, "%.f kB", 2 * (double) scan_count);
1467      sprintf(msg, "Found %d ISO sessions by scanning %s in %.f seconds",
1468              session_count, size_text, (double) (now - start_time));
1469      isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
1470    }
1471    read_flag= 1;
1472    if(flag&2)
1473      read_flag|= (1<<15)|((session_count>0)<<14);
1474    else {
1475 
1476      /* growisofs aligns to 16 rather than 32. Overwriteable TOC emulation
1477         relies on not accidentially seeing inter-session trash data.
1478         But one can safely access 16 blocks earlier because a xorriso header
1479         would have been overwritten with the unused 16 blocks at its start.
1480         If libisoburn alignment would increase, then this would not be
1481         possible any more.
1482      */
1483 
1484      if(probe_minus_16)
1485        read_flag|= (1<<14);
1486      probe_minus_16= 0;
1487    }
1488 
1489    ret= isoburn_read_iso_head(d, lba, &track_blocks, volid, read_flag);
1490    if(ret > 0) {
1491      volid_pt= volid;
1492    } else {
1493      volid_pt= NULL;
1494      if(session_count>0) {
1495        if(flag&2) {
1496          if(ret==0) {
1497            /* try at next 64 k block (check both 32 k halves) */
1498            lba+= 32;
1499            scan_count+= 32;
1500            if(lba-scan_start <= Libisoburn_toc_scan_max_gaP)
1501  continue;
1502          }
1503  break;
1504        }
1505        sprintf(msg,
1506                "Chain of ISO session headers broken at #%d, LBA %ds",
1507                session_count+1, lba);
1508        isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
1509 
1510        if(with_enclosure) {
1511          ret= isoburn_make_toc_entry(o, &session_count, 0, image_size, NULL,0);
1512          if(ret<=0)
1513            goto failure;
1514        }
1515  break; /* do not return failure */
1516 
1517      }
1518      {ret= 0; goto failure;}
1519    }
1520    if(ret==2) /* ISO header was found in first half block */
1521      lba-= 16;
1522 
1523    if(readable_blocks >= 0 && lba + track_blocks > readable_blocks) {
1524      sprintf(msg, "ISO image size %ds larger than readable size %ds",
1525                   lba + track_blocks, readable_blocks);
1526      isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
1527      track_blocks= readable_blocks - lba;
1528    }
1529    ret= isoburn_make_toc_entry(o, &session_count, lba, track_blocks, volid_pt,
1530                                0);
1531    if(ret<=0)
1532      goto failure;
1533    lba+= track_blocks;
1534    scan_count+= 32;
1535 
1536    /* growisofs aligns to 16 rather than 32 */
1537    growisofs_nwa= lba;
1538    if(growisofs_nwa % 16)
1539      growisofs_nwa+= 16 - (growisofs_nwa % 16);
1540    if(lba % Libisoburn_nwa_alignemenT)
1541      lba+= Libisoburn_nwa_alignemenT - (lba % Libisoburn_nwa_alignemenT);
1542    scan_start= lba;
1543    if(lba - growisofs_nwa == 16)
1544      probe_minus_16= 1;
1545  }
1546  if(last_pacifier != start_time)
1547    sev= "UPDATE";
1548  else
1549    sev= "DEBUG";
1550  now= time(NULL);
1551  if(scan_count>=10*512)
1552    sprintf(size_text, "%.f MB", ((double) scan_count) / 512.0);
1553  else
1554    sprintf(size_text, "%.f kB", 2 * (double) scan_count);
1555  sprintf(msg, "Found %d ISO sessions by scanning %s in %.f seconds",
1556          session_count, size_text, (double) (now - start_time));
1557  isoburn_msgs_submit(o, 0x00060000, msg, 0, sev, 0);
1558  {ret= 1; goto ex;}
1559 failure:;
1560  isoburn_toc_entry_destroy(&(o->toc), 1);
1561  if(with_enclosure && o->emulation_mode == 1) {
1562    if(readable_blocks >= 0 && image_size > readable_blocks) {
1563      sprintf(msg, "ISO image size %ds larger than readable size %ds",
1564                   image_size, readable_blocks);
1565      isoburn_msgs_submit(o, 0x00060000, msg, 0, "WARNING", 0);
1566      image_size= readable_blocks;
1567    }
1568    session_count= 0;
1569    ret= isoburn_make_toc_entry(o, &session_count, 0, image_size, NULL, 0);
1570  }
1571 ex:;
1572  if(msg != NULL)
1573    free(msg);
1574  if(size_text != NULL)
1575    free(size_text);
1576  return(ret);
1577 }
1578 
1579 
isoburn_toc_new_arrays(struct isoburn_toc_disc * o,int session_count,int track_count,int flag)1580 int isoburn_toc_new_arrays(struct isoburn_toc_disc *o,
1581                            int session_count, int track_count, int flag)
1582 {
1583  int i;
1584  int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag);
1585 
1586  o->sessions= calloc(session_count, sizeof(struct isoburn_toc_session));
1587  o->session_pointers=
1588                    calloc(session_count, sizeof(struct isoburn_toc_session *));
1589  o->tracks= calloc(track_count, sizeof(struct isoburn_toc_track));
1590  o->track_pointers= calloc(track_count, sizeof(struct isoburn_toc_track *));
1591  if(o->sessions!=NULL && o->session_pointers!=NULL &&
1592     o->tracks!=NULL && o->track_pointers!=NULL) {
1593    for(i= 0; i<session_count; i++) {
1594      o->sessions[i].session= NULL;
1595      o->sessions[i].track_pointers= NULL;
1596      o->sessions[i].track_count= 0;
1597      o->sessions[i].toc_entry= NULL;
1598      o->session_pointers[i]= NULL;
1599    }
1600    for(i= 0; i<track_count; i++) {
1601      o->tracks[i].track= NULL;
1602      o->tracks[i].toc_entry= NULL;
1603      o->track_pointers[i]= NULL;
1604    }
1605    return(1);
1606  }
1607  /* failed */
1608  isoburn_toc_destroy_arrays(o, 0);
1609  return(-1);
1610 }
1611 
1612 
isoburn_toc_destroy_arrays(struct isoburn_toc_disc * o,int flag)1613 int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag)
1614 {
1615  if(o->sessions!=NULL)
1616    free((char *) o->sessions);
1617  o->sessions= NULL;
1618  if(o->session_pointers!=NULL)
1619    free((char *) o->session_pointers);
1620  o->session_pointers= NULL;
1621  if(o->tracks!=NULL)
1622    free((char *) o->tracks);
1623  o->tracks= NULL;
1624  if(o->track_pointers!=NULL)
1625    free((char *) o->track_pointers);
1626  o->track_pointers= NULL;
1627  return(1);
1628 }
1629 
1630 
isoburn_toc_drive_get_disc(struct burn_drive * d)1631 struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d)
1632 {
1633  int ret, session_count= 0, track_count= 0, num_tracks= 0, i, j;
1634  int open_sessions= 0;
1635  struct isoburn *o;
1636  struct isoburn_toc_entry *t;
1637  struct isoburn_toc_disc *toc_disc= NULL;
1638  struct burn_session **s;
1639  struct burn_track **tracks;
1640 
1641  toc_disc= calloc(1, sizeof(struct isoburn_toc_disc));
1642  if(toc_disc==NULL)
1643    return(NULL);
1644  toc_disc->disc= NULL;
1645  toc_disc->sessions= NULL;
1646  toc_disc->session_pointers= NULL;
1647  toc_disc->tracks= NULL;
1648  toc_disc->track_pointers= NULL;
1649  toc_disc->session_count= 0;
1650  toc_disc->incomplete_session_count= 0;
1651  toc_disc->track_count= 0;
1652  toc_disc->toc= NULL;
1653 
1654  /* is the medium emulated multi-session ? */
1655  ret= isoburn_find_emulator(&o, d, 0);
1656  if(ret<0)
1657    goto libburn;
1658  if(o->toc==NULL)
1659    goto libburn;
1660 
1661  /* This is an emulated TOC */
1662  toc_disc->toc= o->toc;
1663  for(t= toc_disc->toc; t!=NULL; t= t->next)
1664    session_count++;
1665  ret= isoburn_toc_new_arrays(toc_disc, session_count, session_count, 0);
1666  if(ret<=0)
1667    goto failure;
1668  t= toc_disc->toc;
1669  for(i= 0; i<session_count; i++) {
1670    toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+i;
1671    toc_disc->sessions[i].track_count= 1;
1672    toc_disc->sessions[i].toc_entry= t;
1673    toc_disc->session_pointers[i]= toc_disc->sessions+i;
1674    toc_disc->tracks[i].toc_entry= t;
1675    toc_disc->track_pointers[i]= toc_disc->tracks+i;
1676    t= t->next;
1677  }
1678  toc_disc->session_count= session_count;
1679  toc_disc->track_count= session_count;
1680  return(toc_disc);
1681 
1682 libburn:;
1683  /* This is a libburn provided TOC */
1684  toc_disc->disc= burn_drive_get_disc(d);
1685  if(toc_disc->disc == NULL) {
1686 failure:;
1687    free((char *) toc_disc);
1688    return(NULL);
1689  }
1690  s= burn_disc_get_sessions(toc_disc->disc, &session_count);
1691  open_sessions= burn_disc_get_incomplete_sessions(toc_disc->disc);
1692  for(i= 0; i < session_count + open_sessions; i++) {
1693    tracks = burn_session_get_tracks(s[i], &num_tracks);
1694    if(i == session_count + open_sessions - 1 && open_sessions > 0) {
1695      /* Do not count the invisible track of the last incomplete session */
1696      num_tracks--;
1697    }
1698    track_count+= num_tracks;
1699  }
1700  if(session_count + open_sessions <= 0 || track_count <= 0)
1701    goto failure;
1702  ret= isoburn_toc_new_arrays(toc_disc, session_count + open_sessions,
1703                              track_count, 0);
1704  if(ret<=0)
1705    goto failure;
1706  track_count= 0;
1707  for(i= 0; i < session_count + open_sessions; i++) {
1708    tracks = burn_session_get_tracks(s[i], &num_tracks);
1709    if(i == session_count + open_sessions - 1 && open_sessions > 0)
1710      num_tracks--;
1711    toc_disc->sessions[i].session= s[i];
1712    toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+track_count;
1713    toc_disc->sessions[i].track_count= num_tracks;
1714    toc_disc->session_pointers[i]= toc_disc->sessions+i;
1715    for(j= 0; j<num_tracks; j++) {
1716      toc_disc->tracks[track_count+j].track= tracks[j];
1717      toc_disc->track_pointers[track_count+j]= toc_disc->tracks+(track_count+j);
1718    }
1719    track_count+= num_tracks;
1720  }
1721  toc_disc->session_count= session_count;
1722  toc_disc->incomplete_session_count= open_sessions;
1723  toc_disc->track_count= track_count;
1724  return(toc_disc);
1725 }
1726 
1727 
isoburn_toc_disc_get_sectors(struct isoburn_toc_disc * disc)1728 int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc)
1729 {
1730  struct isoburn_toc_entry *t;
1731  int ret= 0, num_sessions, num_tracks, open_sessions= 0, session_idx= -1;
1732  struct burn_session **sessions;
1733  struct burn_track **tracks;
1734  struct burn_toc_entry entry;
1735 
1736  if(disc==NULL)
1737    return(0);
1738  if(disc->toc!=NULL) {
1739    for(t= disc->toc; t!=NULL; t= t->next)
1740      ret= t->start_lba + t->track_blocks;
1741  } else if(disc->disc!=NULL) {
1742    sessions= burn_disc_get_sessions(disc->disc, &num_sessions);
1743    open_sessions= burn_disc_get_incomplete_sessions(disc->disc);
1744    if(num_sessions + open_sessions > 0) {
1745      session_idx= num_sessions + open_sessions - 1;
1746      tracks = burn_session_get_tracks(sessions[session_idx], &num_tracks);
1747      if(open_sessions > 0) {
1748        /* Do not count the invisible track of the last incomplete session */
1749        num_tracks--;
1750      }
1751      if(num_tracks <= 0)
1752        session_idx--;
1753    }
1754    if(session_idx >= 0) {
1755      tracks = burn_session_get_tracks(sessions[session_idx], &num_tracks);
1756      if(session_idx == num_sessions + open_sessions - 1 && open_sessions > 0) {
1757        /* Do not count the invisible track of the last incomplete session */
1758        num_tracks--;
1759      }
1760      if(num_tracks > 0) {
1761        burn_track_get_entry(tracks[num_tracks - 1], &entry);
1762        if(entry.extensions_valid & 1)
1763          ret= entry.start_lba + entry.track_blocks;
1764      }
1765    }
1766 /*
1767    ret= burn_disc_get_sectors(disc->disc);
1768 */
1769  }
1770  return(ret);
1771 }
1772 
1773 
isoburn_toc_disc_get_sessions(struct isoburn_toc_disc * disc,int * num)1774 struct isoburn_toc_session **isoburn_toc_disc_get_sessions(
1775                                       struct isoburn_toc_disc *disc, int *num)
1776 {
1777  *num= disc->session_count;
1778  return(disc->session_pointers);
1779 }
1780 
1781 
isoburn_toc_disc_get_incmpl_sess(struct isoburn_toc_disc * disc)1782 int isoburn_toc_disc_get_incmpl_sess(struct isoburn_toc_disc *disc)
1783 {
1784  return(disc->incomplete_session_count);
1785 }
1786 
1787 
isoburn_toc_session_get_sectors(struct isoburn_toc_session * s)1788 int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s)
1789 {
1790  struct isoburn_toc_entry *t;
1791  int count= 0, i;
1792 
1793  if(s==NULL)
1794    return(0);
1795  if(s->toc_entry!=NULL) {
1796    t= s->toc_entry;
1797    for(i= 0; i<s->track_count; i++) {
1798      count+= t->track_blocks;
1799      t= t->next;
1800    }
1801  } else if(s->session!=NULL)
1802    count= burn_session_get_sectors(s->session);
1803  return(count);
1804 }
1805 
1806 
isoburn_toc_entry_finish(struct burn_toc_entry * entry,int session_no,int track_no,int flag)1807 int isoburn_toc_entry_finish(struct burn_toc_entry *entry,
1808                              int session_no, int track_no, int flag)
1809 {
1810  int pmin, psec, pframe;
1811 
1812  entry->extensions_valid= 1;
1813  entry->adr= 1;
1814  entry->control= 4;
1815  entry->session= session_no & 255;
1816  entry->session_msb= (session_no >> 8) & 255;
1817  entry->point= track_no & 255;
1818  entry->point_msb= (track_no >> 8) & 255;
1819 
1820  burn_lba_to_msf(entry->start_lba, &pmin, &psec, &pframe);
1821  if(pmin<=255)
1822    entry->pmin= pmin;
1823  else
1824    entry->pmin= 255;
1825  entry->psec= psec;
1826  entry->pframe= pframe;
1827  return(1);
1828 }
1829 
1830 
isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session * s,struct burn_toc_entry * entry)1831 void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s,
1832                                        struct burn_toc_entry *entry)
1833 {
1834  struct isoburn_toc_track *t;
1835 
1836  if(s==NULL)
1837    return;
1838  if(s->session!=NULL && s->toc_entry==NULL) {
1839    burn_session_get_leadout_entry(s->session, entry);
1840    return;
1841  }
1842  if(s->track_count<=0 || s->track_pointers==NULL || s->toc_entry==NULL)
1843    return;
1844  t= s->track_pointers[s->track_count-1];
1845  entry->start_lba= t->toc_entry->start_lba + t->toc_entry->track_blocks;
1846  entry->track_blocks= 0;
1847  isoburn_toc_entry_finish(entry, s->toc_entry->session, t->toc_entry->track_no,
1848                           0);
1849 }
1850 
1851 
isoburn_toc_session_get_tracks(struct isoburn_toc_session * s,int * num)1852 struct isoburn_toc_track **isoburn_toc_session_get_tracks(
1853                                       struct isoburn_toc_session *s, int *num)
1854 {
1855  *num= s->track_count;
1856  return(s->track_pointers);
1857 }
1858 
1859 
isoburn_toc_track_get_entry(struct isoburn_toc_track * t,struct burn_toc_entry * entry)1860 void isoburn_toc_track_get_entry(struct isoburn_toc_track *t,
1861                                  struct burn_toc_entry *entry)
1862 {
1863  if(t==0)
1864    return;
1865  if(t->track!=NULL && t->toc_entry==NULL) {
1866    burn_track_get_entry(t->track, entry);
1867    return;
1868  }
1869  if(t->toc_entry==NULL)
1870    return;
1871  entry->start_lba= t->toc_entry->start_lba;
1872  entry->track_blocks= t->toc_entry->track_blocks;
1873  isoburn_toc_entry_finish(entry, t->toc_entry->session, t->toc_entry->track_no,
1874                           0);
1875 }
1876 
1877 
isoburn_toc_track_get_emul(struct isoburn_toc_track * t,int * start_lba,int * image_blocks,char volid[33],int flag)1878 int isoburn_toc_track_get_emul(struct isoburn_toc_track *t, int *start_lba,
1879                                int *image_blocks, char volid[33], int flag)
1880 {
1881  if(t->toc_entry == NULL)
1882    return(0);
1883  if(t->toc_entry->volid == NULL)
1884    return(0);
1885  *start_lba= t->toc_entry->start_lba;
1886  *image_blocks= t->toc_entry->track_blocks;
1887  strncpy(volid, t->toc_entry->volid, 32);
1888  volid[32]= 0;
1889  return(1);
1890 }
1891 
1892 
isoburn_toc_disc_free(struct isoburn_toc_disc * d)1893 void isoburn_toc_disc_free(struct isoburn_toc_disc *d)
1894 {
1895  if(d->disc!=NULL)
1896    burn_disc_free(d->disc);
1897  isoburn_toc_destroy_arrays(d, 0);
1898  free((char *) d);
1899 }
1900 
1901 
isoburn_get_track_lba(struct isoburn_toc_track * track,int * lba,int flag)1902 int isoburn_get_track_lba(struct isoburn_toc_track *track, int *lba, int flag)
1903 {
1904  struct burn_toc_entry entry;
1905 
1906  isoburn_toc_track_get_entry(track, &entry);
1907  if (entry.extensions_valid & 1)
1908    *lba= entry.start_lba;
1909  else
1910    *lba= burn_msf_to_lba(entry.pmin, entry.psec, entry.pframe);
1911  return(1);
1912 }
1913 
1914 
isoburn_drive_set_msgs_submit(struct burn_drive * d,int (* msgs_submit)(void * handle,int error_code,char msg_text[],int os_errno,char severity[],int flag),void * submit_handle,int submit_flag,int flag)1915 int isoburn_drive_set_msgs_submit(struct burn_drive *d,
1916                             int (*msgs_submit)(void *handle, int error_code,
1917                                                char msg_text[], int os_errno,
1918                                                char severity[], int flag),
1919                             void *submit_handle, int submit_flag, int flag)
1920 {
1921  struct isoburn *o;
1922  int ret;
1923 
1924  ret= isoburn_find_emulator(&o, d, 0);
1925  if(ret<0 || o==NULL)
1926    return(-1);
1927  o->msgs_submit= msgs_submit;
1928  o->msgs_submit_handle= submit_handle;
1929  o->msgs_submit_flag= submit_flag;
1930  return(1);
1931 }
1932 
1933 
1934 /* @param flag bit0= with adr_mode 3: adr_value might be 16 blocks too high
1935                bit1= insist in seeing a disc object with at least one session
1936                bit2= with adr_mode 4: use adr_value as regular expression
1937 */
isoburn_set_msc1(struct burn_drive * d,int adr_mode,char * adr_value,int flag)1938 int isoburn_set_msc1(struct burn_drive *d, int adr_mode, char *adr_value,
1939                      int flag)
1940 {
1941  int ret, num_sessions= 0, num_tracks, adr_num, i, j, total_tracks;
1942  int lba, best_lba, size, re_valid= 0, track_count= 0;
1943  time_t start_time= 0, last_pacifier= 0, now;
1944  char volid[33], *msg= NULL;
1945  struct isoburn *o;
1946  struct isoburn_toc_disc *disc= NULL;
1947  struct isoburn_toc_session **sessions= NULL;
1948  struct isoburn_toc_track **tracks= NULL;
1949  static char mode_names[][20]= {"auto", "session", "track", "lba", "volid"};
1950  static int max_mode_names= 4;
1951  regex_t re;
1952  regmatch_t match[1];
1953  enum burn_disc_status s;
1954 
1955  ret= isoburn_find_emulator(&o, d, 0);
1956  if(ret<0)
1957    return(-1);
1958  if(o==NULL)
1959    return(-1);
1960 
1961  msg= calloc(1, 160);
1962  if(msg == NULL)
1963    {ret= -1; goto ex;}
1964 
1965  start_time= last_pacifier= time(NULL);
1966  adr_num= atoi(adr_value);
1967  if(adr_mode!=3 || (flag & 2)) {
1968    disc= isoburn_toc_drive_get_disc(d);
1969    if(disc==NULL) {
1970 not_found:;
1971      if(adr_mode<0 || adr_mode>max_mode_names)
1972        goto unknown_mode;
1973      sprintf(msg, "Failed to find %s %s", mode_names[adr_mode],
1974                   strlen(adr_value)<=80 ?  adr_value : "-oversized-string-");
1975      isoburn_msgs_submit(o, 0x00060000, msg, 0, "FAILURE", 0);
1976      ret= 0; goto ex;
1977    }
1978    sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
1979    if(sessions==NULL || num_sessions<=0)
1980      goto not_found;
1981  }
1982  if(adr_mode==0) {
1983    /* Set fabricated_msc1 to last session in TOC */
1984    tracks= isoburn_toc_session_get_tracks(sessions[num_sessions-1],
1985                                           &num_tracks);
1986    if(tracks==NULL || num_tracks<=0)
1987      goto not_found;
1988    isoburn_get_track_lba(tracks[0], &(o->fabricated_msc1), 0);
1989 
1990  } else if(adr_mode==1) {
1991    /* Use adr_num as session index (first session is 1, not 0) */
1992    if(adr_num<1 || adr_num>num_sessions)
1993      goto not_found;
1994    tracks= isoburn_toc_session_get_tracks(sessions[adr_num-1], &num_tracks);
1995    if(tracks==NULL || num_tracks<=0)
1996      goto not_found;
1997    isoburn_get_track_lba(tracks[0], &(o->fabricated_msc1), 0);
1998 
1999  } else if(adr_mode==2) {
2000    /* use adr_num as track index */
2001    total_tracks= 0;
2002    for(i=0; i<num_sessions; i++) {
2003      tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
2004      if(tracks==NULL)
2005    continue;
2006      for(j= 0; j<num_tracks; j++) {
2007        total_tracks++;
2008        if(total_tracks==adr_num) {
2009          isoburn_get_track_lba(tracks[j], &(o->fabricated_msc1), 0);
2010          ret= 1; goto ex;
2011        }
2012      }
2013    }
2014    goto not_found;
2015 
2016  } else if(adr_mode==3) {
2017    o->fabricated_msc1= adr_num;
2018    s= isoburn_disc_get_status(d);
2019    if(o->fabricated_msc1 > 0 && s != BURN_DISC_FULL
2020       && s != BURN_DISC_APPENDABLE) {
2021      isoburn_msgs_submit(o, 0x00060000,
2022                          "Non-zero load offset given with blank input media",
2023                          0, "FAILURE", 0);
2024      ret= 0; goto ex;
2025    }
2026    if((flag & 1) && o->fabricated_msc1 >= 16) {
2027      /* adr_num is possibly 16 blocks too high */
2028      ret= isoburn_read_iso_head(d, o->fabricated_msc1, &size,volid, 1|(1<<14));
2029      if(ret==2)
2030        o->fabricated_msc1-= 16;
2031    }
2032  } else if(adr_mode==4) {
2033    /* search for volume id that is equal to adr_value */
2034    if(flag & 4) {
2035      ret= regcomp(&re, adr_value, 0);
2036      if(ret != 0)
2037        flag&= ~4;
2038      else
2039        re_valid= 1;
2040    }
2041    best_lba= -1;
2042    for(i=0; i<num_sessions; i++) {
2043      tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
2044      if(tracks==NULL)
2045    continue;
2046      for(j= 0; j<num_tracks; j++) {
2047        now= time(NULL);
2048        if(now - last_pacifier >= 5 && track_count > 0) {
2049          last_pacifier= now;
2050          sprintf(msg,
2051                  "Scanned %d tracks for matching volid in %.f seconds",
2052                  track_count, (double) (now - start_time));
2053          isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
2054        }
2055        track_count++;
2056        ret= isoburn_toc_track_get_emul(tracks[0], &lba, &size, volid, 0);
2057        if(ret < 0)
2058      continue;
2059        if(ret == 0) {
2060          isoburn_get_track_lba(tracks[0], &lba, 0);
2061          ret= isoburn_read_iso_head(d, lba, &size, volid, 1);
2062          if(ret<=0)
2063      continue;
2064        }
2065        if(flag & 4) {
2066          ret= regexec(&re, volid, 1, match, 0);
2067          if(ret != 0)
2068      continue;
2069        } else {
2070          if(strcmp(volid, adr_value)!=0)
2071      continue;
2072        }
2073        best_lba= lba;
2074      }
2075    }
2076    if(best_lba<0)
2077      goto not_found;
2078    o->fabricated_msc1= best_lba;
2079 
2080  } else {
2081 unknown_mode:;
2082    sprintf(msg, "Program error: Unknown msc1 address mode %d", adr_mode);
2083    isoburn_msgs_submit(o, 0x00060000, msg, 0, "FATAL", 0);
2084    ret= 0; goto ex;
2085  }
2086  ret= 1;
2087 ex:;
2088  if(start_time != last_pacifier && track_count > 0) {
2089    now= time(NULL);
2090    sprintf(msg,
2091            "Scanned %d tracks for matching volid in %.f seconds",
2092            track_count, (double) (now - start_time));
2093    isoburn_msgs_submit(o, 0x00060000, msg, 0, "UPDATE", 0);
2094  }
2095  if(disc!=NULL)
2096    isoburn_toc_disc_free(disc);
2097  if((flag & 4) && re_valid)
2098    regfree(&re);
2099  if(msg != NULL)
2100    free(msg);
2101  return(ret);
2102 }
2103 
2104 
isoburn_get_mount_params(struct burn_drive * d,int adr_mode,char * adr_value,int * lba,int * track,int * session,char volid[33],int flag)2105 int isoburn_get_mount_params(struct burn_drive *d,
2106                              int adr_mode, char *adr_value,
2107                              int *lba, int *track, int *session,
2108                              char volid[33], int flag)
2109 {
2110  int msc1_mem, ret, total_tracks, num_sessions, num_tracks, i, j, track_lba;
2111  int size, is_iso= 0;
2112  struct isoburn *o;
2113  struct isoburn_toc_disc *disc= NULL;
2114  struct isoburn_toc_session **sessions= NULL;
2115  struct isoburn_toc_track **tracks= NULL;
2116 
2117  *lba= *track= *session= -1;
2118  volid[0]= 0;
2119  ret= isoburn_find_emulator(&o, d, 0);
2120  if(ret < 0 || o == NULL)
2121    return(-1);
2122  msc1_mem= o->fabricated_msc1;
2123  ret= isoburn_set_msc1(d, adr_mode, adr_value, 2 | (flag & 4));
2124  if(ret <= 0)
2125    return(ret);
2126  *lba= o->fabricated_msc1;
2127 
2128  disc= isoburn_toc_drive_get_disc(d);
2129  if(disc==NULL)
2130    {ret= -1; goto ex;} /* cannot happen because checked by isoburn_set_msc1 */
2131  sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
2132  if(sessions==NULL || num_sessions<=0)
2133    {ret= -1; goto ex;} /* cannot happen because checked by isoburn_set_msc1 */
2134  total_tracks= 0;
2135  for(i=0; i<num_sessions && *session < 0; i++) {
2136    tracks= isoburn_toc_session_get_tracks(sessions[i], &num_tracks);
2137    if(tracks==NULL)
2138  continue;
2139    for(j= 0; j<num_tracks && *track < 0; j++) {
2140      total_tracks++;
2141      isoburn_get_track_lba(tracks[j], &track_lba, 0);
2142      if(track_lba == *lba) {
2143        *track= total_tracks;
2144        *session= i + 1;
2145      }
2146    }
2147  }
2148  ret= isoburn_read_iso_head(d, *lba, &size, volid, 1);
2149  if(ret <= 0)
2150    volid[0]= 0;
2151  else
2152    is_iso= 1;
2153 
2154 ex:;
2155  o->fabricated_msc1= msc1_mem;
2156  if(disc != NULL)
2157    isoburn_toc_disc_free(disc);
2158  return(2 - is_iso);
2159 }
2160 
2161 
2162