/* cc -g -c \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \ burn_wrap.c */ /* libburn wrappers for libisoburn Copyright 2007 - 2008 Thomas Schmitt, */ /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo #define Hardcoded_cd_rW 1 #define Hardcoded_cd_rw_c1 12999 #define Hardcoded_cd_rw_nwA 152660 */ #include #include #include #include #include #include #include #include #ifndef Xorriso_standalonE #include #include #else /* ! Xorriso_standalonE */ #include "../libisofs/libisofs.h" #include "../libburn/libburn.h" #endif /* Xorriso_standalonE */ /* <<< remove macro and alternative outdated code */ #define Libisoburn_on__libburn_after_0_4_2 yes #include "libisoburn.h" #include "isoburn.h" /* The global list of isoburn objects. Usually there is only one. */ extern struct isoburn *isoburn_list_start; /* in isoburn.c */ int isoburn_emulate_toc(struct burn_drive *d, int flag); int isoburn_initialize(char msg[1024], int flag) { int major, minor, micro, bad_match= 0; /* First two ugly compile time checks for header version compatibility. If everthing matches, then they produce no C code. In case of mismatch, intentionally faulty C code will be inserted. */ #ifdef iso_lib_header_version_major /* The minimum requirement of libisoburn towards the libisofs header at compile time is defined in libisoburn/libisoburn.h : isoburn_libisofs_req_major isoburn_libisofs_req_minor isoburn_libisofs_req_micro It gets compared against the version macros in libisofs/libisofs.h : iso_lib_header_version_major iso_lib_header_version_minor iso_lib_header_version_micro If the header is too old then the following code shall cause failure of cdrskin compilation rather than to allow production of a program with unpredictable bugs or memory corruption. The compiler messages supposed to appear in this case are: error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function) 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) error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function) */ /* The indendation is an advise of man gcc to help old compilers ignoring */ #if isoburn_libisofs_req_major > iso_lib_header_version_major #define Isoburn_libisofs_dot_h_too_olD 1 #endif #if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor #define Isoburn_libisofs_dot_h_too_olD 1 #endif #if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro #define Isoburn_libisofs_dot_h_too_olD 1 #endif #ifdef Isoburn_libisofs_dot_h_too_olD LIBISOFS_MISCONFIGURATION = 0; INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0; LIBISOFS_MISCONFIGURATION_ = 0; #endif #endif /* iso_lib_header_version_major */ /* The minimum requirement of libisoburn towards the libburn header at compile time is defined in libisoburn/libisoburn.h : isoburn_libburn_req_major isoburn_libburn_req_minor isoburn_libburn_req_micro It gets compared against the version macros in libburn/libburn.h : burn_header_version_major burn_header_version_minor burn_header_version_micro If the header is too old then the following code shall cause failure of cdrskin compilation rather than to allow production of a program with unpredictable bugs or memory corruption. The compiler messages supposed to appear in this case are: error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function) 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) error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function) */ /* The indendation is an advise of man gcc to help old compilers ignoring */ #if isoburn_libburn_req_major > burn_header_version_major #define Isoburn_libburn_dot_h_too_olD 1 #endif #if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor #define Isoburn_libburn_dot_h_too_olD 1 #endif #if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro #define Isoburn_libburn_dot_h_too_olD 1 #endif #ifdef Isoburn_libburn_dot_h_too_olD LIBBURN_MISCONFIGURATION = 0; INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0; LIBBURN_MISCONFIGURATION_ = 0; #endif /* End of ugly compile time tests (scroll up for explanation) */ msg[0]= 0; if(iso_init()<0) { sprintf(msg+strlen(msg), "Cannot initialize libisofs\n"); return(0); } iso_lib_version(&major, &minor, µ); sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro); #ifdef iso_lib_header_version_major if(iso_lib_is_compatible(iso_lib_header_version_major, iso_lib_header_version_minor, iso_lib_header_version_micro)) { sprintf(msg+strlen(msg), "ok, "); } else { sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n", iso_lib_header_version_major, iso_lib_header_version_minor, iso_lib_header_version_micro); bad_match= 1; } #else if(iso_lib_is_compatible(isoburn_libisofs_req_major, isoburn_libisofs_req_minor, isoburn_libisofs_req_micro)) { sprintf(msg+strlen(msg), "suspicious, "); } else { sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n", isoburn_libisofs_req_major, isoburn_libisofs_req_minor, isoburn_libisofs_req_micro); bad_match= 1; } #endif /* ! iso_lib_header_version_major */ if(!burn_initialize()) { sprintf(msg+strlen(msg), "Cannot initialize libburn\n"); return(0); } burn_version(&major, &minor, µ); sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro); if(major > burn_header_version_major || (major == burn_header_version_major && (minor > burn_header_version_minor || (minor == burn_header_version_minor && micro >= burn_header_version_micro)))) { sprintf(msg+strlen(msg), "ok, "); } else { sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n", burn_header_version_major, burn_header_version_minor, burn_header_version_micro); bad_match= 1; } isoburn_version(&major, &minor, µ); sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro); if(bad_match) return(0); isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */ return(1); } /* API @since 0.1.0 */ int isoburn_libisofs_req(int *major, int *minor, int *micro) { *major= iso_lib_header_version_major; *minor= iso_lib_header_version_minor; *micro= iso_lib_header_version_micro; return(1); } /* API @since 0.1.0 */ int isoburn_libburn_req(int *major, int *minor, int *micro) { *major= burn_header_version_major; *minor= burn_header_version_minor; *micro= burn_header_version_micro; return(1); } int isoburn_is_intermediate_dvd_rw(struct burn_drive *d, int flag) { int profile, ret= 0, format_status, num_formats; char profile_name[80]; enum burn_disc_status s; off_t format_size= -1; unsigned bl_sas; s= isoburn_disc_get_status(d); ret= burn_disc_get_profile(d, &profile, profile_name); if(ret>0 && profile==0x13) ret= burn_disc_get_formats(d, &format_status, &format_size, &bl_sas, &num_formats); if(ret>0 && profile==0x13 && s==BURN_DISC_BLANK && format_status==BURN_FORMAT_IS_UNKNOWN) return(1); return(0); } /** Examines the media and sets appropriate emulation if needed. @param flag bit0= pretent blank on overwriteable media */ static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d, int flag) { int ret, lba, nwa; struct burn_multi_caps *caps= NULL; ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0); if(ret<0) /* == 0 is read-only media, but it is too early to reject it here */ goto ex; ret= isoburn_new(o, 0); if(ret<=0) goto ex; (*o)->drive= d; #ifdef Hardcoded_cd_rW /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */ caps->start_adr= 0; (*o)->fabricated_disc_status= BURN_DISC_APPENDABLE; #endif if(caps->start_adr) { /* set emulation to overwriteable */ (*o)->emulation_mode= 1; ret= isoburn_is_intermediate_dvd_rw(d, 0); if(ret>0) { (*o)->min_start_byte= 0; (*o)->nwa= 0; (*o)->zero_nwa= 0; } if(flag&1) { (*o)->nwa= (*o)->zero_nwa; (*o)->fabricated_disc_status= BURN_DISC_BLANK; } else { ret= isoburn_start_emulation(*o, 0); if(ret<=0) { (*o)->emulation_mode= -1; goto ex; } /* try to read emulated toc */ ret= isoburn_emulate_toc(d, 0); if(ret<0) { (*o)->emulation_mode= -1; goto ex; } } } else { /* >>> recognize unsuitable media (but allow read-only media) */; #ifdef Hardcoded_cd_rW (*o)->nwa= Hardcoded_cd_rw_nwA; #else ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa); if(ret>0) (*o)->nwa= nwa; #endif } ret= 1; ex: if(caps!=NULL) burn_disc_free_multi_caps(&caps); return(ret); } /** @param flag bit0= load bit1= regard overwriteable media as blank bit2= if the drive is a regular disk file: truncate it to the write start address */ int isoburn_drive_aquire(struct burn_drive_info *drive_infos[], char *adr, int flag) { int ret, conv_ret, drive_grabbed= 0; char libburn_drive_adr[BURN_DRIVE_ADR_LEN]; struct isoburn *o= NULL; char msg[BURN_MSGS_MESSAGE_LEN+4096]; conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr); if(conv_ret<=0) { sprintf(msg, "Unsuitable drive address: '%s'\n",adr); msg[BURN_MSGS_MESSAGE_LEN-1]= 0; burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL); ret= 0; goto ex; } ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, flag&1); if(ret<=0) goto ex; drive_grabbed= 1; ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, !!(flag&2)); if(ret<=0) goto ex; if(flag&4) { ret= isoburn_find_emulator(&o, (*drive_infos)[0].drive, 0); if(ret>0 && o!=NULL) o->truncate= 1; } ret= 1; ex: if(ret<=0) { if(drive_grabbed) burn_drive_release((*drive_infos)[0].drive, 0); isoburn_destroy(&o, 0); } return(ret); } int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[], char *adr, int load) { int ret; ret= isoburn_drive_aquire(drive_infos, adr, !!load); return(ret); } int isoburn_drive_grab(struct burn_drive *drive, int load) { int ret; struct isoburn *o= NULL; ret= burn_drive_grab(drive, load); if(ret<=0) goto ex; ret= isoburn_welcome_media(&o, drive, 0); if(ret<=0) goto ex; ret= 1; ex: if(ret<=0) isoburn_destroy(&o,0); return(ret); } /** Retrieve media emulation and eventual isoburn emulator of drive. @return -1 unsuitable media, 0 generic media, 1 emulated media. */ int isoburn_find_emulator(struct isoburn **pt, struct burn_drive *drive, int flag) { int ret; ret= isoburn_find_by_drive(pt, drive, 0); if(ret<=0) return(0); if((*pt)->emulation_mode==-1) { burn_msgs_submit(0x00060000, "Unsuitable drive and media state", 0, "FAILURE", NULL); return(-1); } if((*pt)->emulation_mode==0) return(0); return(1); } enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, drive, 0); if(ret<0) return(BURN_DISC_UNSUITABLE); if(o!=NULL) if(o->fabricated_disc_status!=BURN_DISC_UNREADY) return(o->fabricated_disc_status); if(ret==0) return(burn_disc_get_status(drive)); /* emulated status */ if(o->emulation_mode==-1) return(BURN_DISC_UNSUITABLE); if(o->nwa>o->zero_nwa) return(BURN_DISC_APPENDABLE); return(BURN_DISC_BLANK); } int isoburn_disc_erasable(struct burn_drive *d) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, d, 0); if(ret>0) if(o->emulation_mode==1) return(1); return burn_disc_erasable(d); } void isoburn_disc_erase(struct burn_drive *drive, int fast) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, drive, 0); if(ret>0) { if(o->emulation_mode==-1) { /* To cause a negative reply with burn_drive_wrote_well() */ burn_drive_cancel(drive); return; } if(o->emulation_mode>0) { ret= isoburn_invalidate_iso(o, 0); if(ret<=0) burn_drive_cancel(drive); return; } } burn_disc_erase(drive, fast); } off_t isoburn_disc_available_space(struct burn_drive *d, struct burn_write_opts *opts) { int ret; struct isoburn *o; struct burn_write_opts *eff_opts= NULL, *local_opts= NULL; off_t avail; eff_opts= opts; ret= isoburn_find_emulator(&o, d, 0); if(ret>0 && o!=NULL) if(o->emulation_mode!=0) { local_opts= burn_write_opts_new(d); eff_opts= local_opts; burn_write_opts_set_start_byte(eff_opts, ((off_t) o->nwa) * (off_t) 2048); } avail= burn_disc_available_space(d, eff_opts); if(local_opts!=NULL) burn_write_opts_free(local_opts); local_opts= NULL; return(avail); } int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba) { int ret; struct isoburn *o; #ifdef Hardcoded_cd_rW /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */ *start_lba= Hardcoded_cd_rw_c1; return(1); #endif if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE && isoburn_disc_get_status(d)!=BURN_DISC_FULL) { burn_msgs_submit(0x00060000, "Media contains no recognizable data", 0, "SORRY",NULL); return(0); } ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(0); if(ret>0) if(o->emulation_mode>0) { *start_lba= 0; return(1); } return(burn_disc_get_msc1(d, start_lba)); } int isoburn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *opts, int trackno, int *lba, int *nwa) { int ret; struct isoburn *o; #ifdef Hardcoded_cd_rW /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */ *lba= Hardcoded_cd_rw_c1; *nwa= Hardcoded_cd_rw_nwA; return(1); #endif *nwa= *lba= 0; ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(0); if(ret>0) if(o->emulation_mode>0) { *lba= 0; *nwa= o->nwa; return(1); } if(burn_drive_get_drive_role(d) != 1) return(1); return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa)); } void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) { int ret; off_t nwa= 0; struct isoburn *o; struct burn_drive *drive; char reasons[BURN_REASONS_LEN],msg[160+BURN_REASONS_LEN]; char adr[BURN_DRIVE_ADR_LEN]; enum burn_write_types write_type; struct stat stbuf; drive= burn_write_opts_get_drive(opts); ret= isoburn_find_emulator(&o, drive, 0); if(ret<0) return; if(o!=NULL) { o->wrote_well= -1; if(o->emulation_mode!=0) { burn_write_opts_set_multi(opts, 0); if(o->emulation_mode>0 && o->nwa >= 0) { nwa= o->nwa; /* This caters for unwritten formatted DVD-RW. They need to be written sequentially on the first use. Only written areas are random access. If the first session is not written to LBA 0, then re-opening of formatting and padding is needed. This can be done. But when the track gets closed after padding, this lasts a long time. There is a high risk that an app will not poll the message queue while waiting for isoburn_disc_write() to return. The pacifier loop usually happens only afterwards. So automatic formatting might cause a nervous clueless user. */ ret= isoburn_is_intermediate_dvd_rw(drive, 0); if(ret>0 && nwa>0 && nwa <= o->zero_nwa) { /* actually this should not happen since such media get recognized by isoburn_welcome_media and o->zero_nwa gets set to 0 */ sprintf(msg, "DVD-RW insufficiently formatted. (Intermediate State, size unknown)"); burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL); sprintf(msg, "It might help to first deformat it and then format it again"); burn_msgs_submit(0x00060000, msg, 0, "HINT", NULL); burn_drive_cancel(drive); /* mark run as failure */ return; } /* end of DVD-RW oriented check */ burn_write_opts_set_start_byte(opts, nwa * (off_t) 2048); } } } write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0); if (write_type == BURN_WRITE_NONE) { sprintf(msg, "Failed to find a suitable write mode:\n%s", reasons); burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL); if(o!=NULL) o->wrote_well= 0; /* To cause a negative reply with burn_drive_wrote_well() */ burn_drive_cancel(drive); return; } sprintf(reasons, "%d", (int) write_type); sprintf(msg, "Write_type = %s\n", (write_type == BURN_WRITE_SAO ? "SAO" : (write_type == BURN_WRITE_TAO ? "TAO" : reasons))); burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL); #ifdef Hardcoded_cd_rW /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */ fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA); burn_write_opts_set_start_byte(opts, ((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048); #endif if(o->truncate) { ret= burn_drive_get_drive_role(drive); if(ret==2) { ret= burn_drive_d_get_adr(drive, adr); if(ret>0) { ret= lstat(adr, &stbuf); if(ret!=-1) if(S_ISREG(stbuf.st_mode)) truncate(adr, nwa * (off_t) 2048); } } } burn_disc_write(opts, disc); } void isoburn_drive_release(struct burn_drive *drive, int eject) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, drive, 0); if(ret<0) return; if(o!=NULL) { isoburn_destroy(&o, 0); } burn_drive_release(drive, eject); } void isoburn_finish(void) { isoburn_destroy_all(&isoburn_list_start, 0); burn_finish(); iso_finish(); } int isoburn_needs_emulation(struct burn_drive *drive) { int ret; struct isoburn *o; enum burn_disc_status s; s= isoburn_disc_get_status(drive); if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE) return(-1); ret= isoburn_find_emulator(&o, drive, 0); if(ret<0) return(-1); if(ret>0) if(o->emulation_mode>0) return(1); return(0); } int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag) { int ret; struct burn_drive *drive = o->drive; struct burn_multi_caps *caps= NULL; ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0); if(ret<=0) goto ex; if(!caps->start_adr) { burn_msgs_submit(0x00060000, "Cannot set start byte address with this type of media", 0, "FAILURE", NULL); {ret= 0; goto ex;} } o->min_start_byte= value; if(value % caps->start_alignment) value+= caps->start_alignment - (value % caps->start_alignment); o->nwa= value/2048; /* If suitable for media alignment, round up to Libisoburn_nwa_alignemenT */ if((o->nwa % Libisoburn_nwa_alignemenT) && ((Libisoburn_nwa_alignemenT*2048) % caps->start_alignment)==0 ) o->nwa+= Libisoburn_nwa_alignemenT - (o->nwa % Libisoburn_nwa_alignemenT); ret= 1; ex: if(caps!=NULL) burn_disc_free_multi_caps(&caps); return(ret); } int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte, int flag) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(-1); if(ret==0) return(0); *start_byte= o->min_start_byte; if(o->min_start_byte<=0) return(0); return(1); } int isoburn_drive_wrote_well(struct burn_drive *d) { int ret; struct isoburn *o; ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(-1); if(o!=NULL) if(o->wrote_well>=0) return(o->wrote_well); ret= burn_drive_wrote_well(d); return ret; } int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes, char **status_text) { int ret; struct isoburn *o; size_t hsize= 0, hfree_bytes= 0; ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(-1); if(o==NULL) return(-1); if(o->iso_source==NULL) return(-1); ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes); if(hsize > 1024*1024*1024) *size= 1024*1024*1024; else *size= hsize; if(hfree_bytes > 1024*1024*1024) *free_bytes= 1024*1024*1024; else *free_bytes= hfree_bytes; *status_text= ""; if(ret==0) *status_text= "standby"; else if(ret==1) *status_text= "active"; else if(ret==2) *status_text= "ending"; else if(ret==3) *status_text= "failing"; else if(ret==4) *status_text= "unused"; else if(ret==5) *status_text= "abandoned"; else if(ret==6) *status_text= "ended"; else if(ret==7) *status_text= "aborted"; return(ret); } /* >>> todo: throw out the copies of libdax_msgs entrails */ #ifndef Libisoburn_on__libburn_after_0_4_2 /* <<< to be replaced by libburn-0.4.3 API call burn_sev_to_text(). This is a copy of libdax_msgs__sev_to_text() which is not exposed by the API of of libburn-0.4.2 . As soon as xorriso gets based on libburn-0.4.4 this redundancy is to be removed. It is safe, nevertheless, because the severity codes are eternal. */ #define LIBDAX_MSGS_SEV_ALL 0x00000000 #define LIBDAX_MSGS_SEV_ERRFILE 0x08000000 #define LIBDAX_MSGS_SEV_DEBUG 0x10000000 #define LIBDAX_MSGS_SEV_UPDATE 0x20000000 #define LIBDAX_MSGS_SEV_NOTE 0x30000000 #define LIBDAX_MSGS_SEV_HINT 0x40000000 #define LIBDAX_MSGS_SEV_WARNING 0x50000000 #define LIBDAX_MSGS_SEV_SORRY 0x60000000 #define LIBDAX_MSGS_SEV_MISHAP 0x64000000 #define LIBDAX_MSGS_SEV_FAILURE 0x68000000 #define LIBDAX_MSGS_SEV_FATAL 0x70000000 #define LIBDAX_MSGS_SEV_ABORT 0x71000000 #define LIBDAX_MSGS_SEV_NEVER 0x7fffffff #endif /* ! Libisoburn_on__libburn_after_0_4_2 */ /* @param flag bit0= -reserved- bit1= this is a libburn severity */ int isoburn__sev_to_text(int severity, char **severity_name, int flag) { int ret; ret= iso_sev_to_text(severity, severity_name); if(ret>0) return(ret); #ifdef Libisoburn_on__libburn_after_0_4_2 ret= burn_sev_to_text(severity, severity_name, 0); return(ret); #else if(flag&1) { *severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL"; return(1); } *severity_name= ""; if(severity>=LIBDAX_MSGS_SEV_NEVER) *severity_name= "NEVER"; else if(severity>=LIBDAX_MSGS_SEV_ABORT) *severity_name= "ABORT"; else if(severity>=LIBDAX_MSGS_SEV_FATAL) *severity_name= "FATAL"; else if(severity>=LIBDAX_MSGS_SEV_FAILURE) *severity_name= "FAILURE"; else if(severity>=LIBDAX_MSGS_SEV_MISHAP) *severity_name= "MISHAP"; else if(severity>=LIBDAX_MSGS_SEV_SORRY) *severity_name= "SORRY"; else if(severity>=LIBDAX_MSGS_SEV_WARNING) *severity_name= "WARNING"; else if(severity>=LIBDAX_MSGS_SEV_HINT) *severity_name= "HINT"; else if(severity>=LIBDAX_MSGS_SEV_NOTE) *severity_name= "NOTE"; else if(severity>=LIBDAX_MSGS_SEV_UPDATE) *severity_name= "UPDATE"; else if(severity>=LIBDAX_MSGS_SEV_DEBUG) *severity_name= "DEBUG"; else if(severity>=LIBDAX_MSGS_SEV_ERRFILE) *severity_name= "ERRFILE"; else if(severity>=LIBDAX_MSGS_SEV_ALL) *severity_name= "ALL"; else { *severity_name= ""; return(0); } return(1); #endif /* ! Libisoburn_on__libburn_after_0_4_2 */ } int isoburn__text_to_sev(char *severity_name, int *severity_number, int flag) { int ret= 1; ret= iso_text_to_sev(severity_name, severity_number); if(ret>0) return(ret); #ifndef Libisoburn_on__libburn_after_0_4_2 if(severity_name[0]==0) *severity_number= 0; else if(strcmp(severity_name, "MISHAP")==0) *severity_number= LIBDAX_MSGS_SEV_MISHAP; else if(strcmp(severity_name, "ERRFILE")==0) *severity_number= LIBDAX_MSGS_SEV_ERRFILE; else #endif /* ! Libisoburn_on__libburn_after_0_4_2 */ ret= burn_text_to_sev(severity_name, severity_number, 0); return(ret); } int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno, char min_severity[], int flag) { int error_code, iso_sev, min_sev, ret; char *sev_text_pt, *msg_text_pt= NULL; error_code= iso_error_get_code(iso_error_code); if(error_code < 0x00030000 || error_code >= 0x00040000) error_code= (error_code & 0xffff) | 0x00050000; if(iso_error_code<0) msg_text_pt= (char *) iso_error_to_msg(iso_error_code); if(msg_text_pt==NULL) msg_text_pt= msg_text; iso_sev= iso_error_get_severity(iso_error_code); sev_text_pt= min_severity; isoburn__text_to_sev(min_severity, &min_sev, 0); if(min_sev < iso_sev) isoburn__sev_to_text(iso_sev, &sev_text_pt, 0); ret= iso_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, 0); return(ret); } /* API @param flag bit0-7: info return mode 0= do not return anything in info (do not even touch it) 1= return volume id @return 1 seems to be a valid ISO image , 0 format not recognized, <0 error */ int isoburn_read_iso_head(struct burn_drive *d, int lba, int *image_blocks, char *info, int flag) { unsigned char buffer[64*1024], *data; int ret, i, info_mode; off_t data_count; *image_blocks= 0; ret = burn_read_data(d, ((off_t) lba) * (off_t) 2048, (char *) buffer, (off_t) 64*1024, &data_count, 2); /* no error messages */ if(ret<=0) return(0); data= buffer+32*1024; /* is this an ISO image ? */ if(data[0]!=1) return(0); if(strncmp((char *) (data+1),"CD001",5)!=0) return(0); *image_blocks= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24); info_mode= flag&255; if(info_mode==0) { ; } else if(info_mode==1) { strncpy(info, (char *) (data+40), 32); info[32]= 0; for(i= strlen(info)-1; i>=0; i--) if(info[i]!=' ') break; else info[i]= 0; } else { burn_msgs_submit(0x00060000, "Program error: Unknown info mode with isoburn_read_iso_head()", 0, "FATAL", NULL); return(-1); } return(1); } int isoburn_emulate_toc(struct burn_drive *d, int flag) { int ret, image_size= 0, lba, track_blocks, session_count= 0; struct isoburn *o; struct isoburn_toc_entry *item; char msg[160]; /* is the media emulated multi-session ? */ ret= isoburn_find_emulator(&o, d, 0); if(ret<0) return(-1); if(o==NULL) return(-1); if(o->emulation_mode<=0) return(0); lba= 0; ret= isoburn_read_iso_head(d, lba, &image_size, NULL, 0); if(ret<=0) {ret= 0; goto failure;} lba= Libisoburn_overwriteable_starT; while(lba0) { sprintf(msg, "Chain of ISO session headers broken at #%d, LBA %ds", session_count+1, lba); burn_msgs_submit(0x00060000, msg, 0, "WARNING", NULL); } {ret= 0; goto failure;} } ret= isoburn_toc_entry_new(&item, o->toc, 0); if(ret<=0) { burn_msgs_submit(0x00060000, "Not enough memory for emulated TOC entry object", 0, "FATAL", NULL); ret= -1; goto failure; } if(o->toc==NULL) o->toc= item; session_count++; item->session= session_count; item->track_no= session_count; item->start_lba= lba; item->track_blocks= track_blocks; lba+= track_blocks; if(lba % Libisoburn_nwa_alignemenT) lba+= Libisoburn_nwa_alignemenT - (lba % Libisoburn_nwa_alignemenT); } sprintf(msg, "Chain of ISO session headers yielded %d sessions", session_count); burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL); return(1); failure:; isoburn_toc_entry_destroy(&(o->toc), 1); return(ret); } int isoburn_toc_new_arrays(struct isoburn_toc_disc *o, int session_count, int track_count, int flag) { int i; int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag); o->sessions= calloc(session_count, sizeof(struct isoburn_toc_session)); o->session_pointers= calloc(session_count, sizeof(struct isoburn_toc_session *)); o->tracks= calloc(track_count, sizeof(struct isoburn_toc_track)); o->track_pointers= calloc(track_count, sizeof(struct isoburn_toc_track *)); if(o->sessions!=NULL && o->session_pointers!=NULL && o->tracks!=NULL && o->track_pointers!=NULL) { for(i= 0; isessions[i].session= NULL; o->sessions[i].track_pointers= NULL; o->sessions[i].track_count= 0; o->sessions[i].toc_entry= NULL; o->session_pointers[i]= NULL; } for(i= 0; itracks[i].track= NULL; o->tracks[i].toc_entry= NULL; o->track_pointers[i]= NULL; } return(1); } /* failed */ isoburn_toc_destroy_arrays(o, 0); return(-1); } int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag) { if(o->sessions!=NULL) free((char *) o->sessions); o->sessions= NULL; if(o->session_pointers!=NULL) free((char *) o->session_pointers); o->session_pointers= NULL; if(o->tracks!=NULL) free((char *) o->tracks); o->tracks= NULL; if(o->track_pointers!=NULL) free((char *) o->track_pointers); o->track_pointers= NULL; return(1); } struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d) { int ret, session_count= 0, track_count= 0, num_tracks= 0, i, j; struct isoburn *o; struct isoburn_toc_entry *t; struct isoburn_toc_disc *toc_disc= NULL; struct burn_session **s; struct burn_track **tracks; toc_disc= calloc(1, sizeof(struct isoburn_toc_disc)); if(toc_disc==NULL) return(NULL); toc_disc->disc= NULL; toc_disc->sessions= NULL; toc_disc->session_pointers= NULL; toc_disc->tracks= NULL; toc_disc->track_pointers= NULL; toc_disc->session_count= 0; toc_disc->track_count= 0; toc_disc->toc= NULL; /* is the media emulated multi-session ? */ ret= isoburn_find_emulator(&o, d, 0); if(ret<=0) goto libburn; if(o->toc==NULL) goto libburn; /* This is an emulated TOC */ toc_disc->toc= o->toc; for(t= toc_disc->toc; t!=NULL; t= t->next) session_count++; ret= isoburn_toc_new_arrays(toc_disc, session_count, session_count, 0); if(ret<=0) goto failure; t= toc_disc->toc; for(i= 0; isessions[i].track_pointers= toc_disc->track_pointers+i; toc_disc->sessions[i].track_count= 1; toc_disc->sessions[i].toc_entry= t; toc_disc->session_pointers[i]= toc_disc->sessions+i; toc_disc->tracks[i].toc_entry= t; toc_disc->track_pointers[i]= toc_disc->tracks+i; t= t->next; } toc_disc->session_count= session_count; toc_disc->track_count= session_count; return(toc_disc); libburn:; /* This is a libburn provided TOC */ toc_disc->disc= burn_drive_get_disc(d); if(toc_disc->disc == NULL) { failure:; free((char *) toc_disc); return(NULL); } s= burn_disc_get_sessions(toc_disc->disc, &session_count); for(i= 0; isessions[i].session= s[i]; toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+track_count; toc_disc->sessions[i].track_count= num_tracks; toc_disc->session_pointers[i]= toc_disc->sessions+i; for(j= 0; jtracks[track_count+j].track= tracks[j]; toc_disc->track_pointers[track_count+j]= toc_disc->tracks+(track_count+j); } track_count+= num_tracks; } toc_disc->session_count= session_count; toc_disc->track_count= track_count; return(toc_disc); } int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc) { struct isoburn_toc_entry *t; int ret= 0; if(disc==NULL) return(0); if(disc->toc!=NULL) { for(t= disc->toc; t!=NULL; t= t->next) ret= t->start_lba + t->track_blocks; } else if(disc->disc!=NULL) ret= burn_disc_get_sectors(disc->disc); return(ret); } struct isoburn_toc_session **isoburn_toc_disc_get_sessions( struct isoburn_toc_disc *disc, int *num) { *num= disc->session_count; return(disc->session_pointers); } int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s) { struct isoburn_toc_entry *t; int count= 0, i; if(s==NULL) return(0); if(s->toc_entry!=NULL) { t= s->toc_entry; for(i= 0; itrack_count; i++) { count+= t->track_blocks; t= t->next; } } else if(s->session!=NULL) count= burn_session_get_sectors(s->session); return(count); } int isoburn_toc_entry_finish(struct burn_toc_entry *entry, int session_no, int track_no, int flag) { int pmin, psec, pframe; entry->extensions_valid= 1; entry->adr= 1; entry->control= 4; entry->session= session_no & 255; entry->session_msb= (session_no >> 8) & 255; entry->point= track_no & 255; entry->point_msb= (track_no >> 8) & 255; burn_lba_to_msf(entry->start_lba, &pmin, &psec, &pframe); if(pmin<=255) entry->pmin= pmin; else entry->pmin= 255; entry->psec= psec; entry->pframe= pframe; return(1); } void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s, struct burn_toc_entry *entry) { struct isoburn_toc_track *t; if(s==NULL) return; if(s->session!=NULL && s->toc_entry==NULL) { burn_session_get_leadout_entry(s->session, entry); return; } if(s->track_count<=0 || s->track_pointers==NULL || s->toc_entry==NULL) return; t= s->track_pointers[s->track_count-1]; entry->start_lba= t->toc_entry->start_lba + t->toc_entry->track_blocks; entry->track_blocks= 0; isoburn_toc_entry_finish(entry, s->toc_entry->session, t->toc_entry->track_no, 0); } struct isoburn_toc_track **isoburn_toc_session_get_tracks( struct isoburn_toc_session *s, int *num) { *num= s->track_count; return(s->track_pointers); } void isoburn_toc_track_get_entry(struct isoburn_toc_track *t, struct burn_toc_entry *entry) { if(t==0) return; if(t->track!=NULL && t->toc_entry==NULL) { burn_track_get_entry(t->track, entry); return; } if(t->toc_entry==NULL) return; entry->start_lba= t->toc_entry->start_lba; entry->track_blocks= t->toc_entry->track_blocks; isoburn_toc_entry_finish(entry, t->toc_entry->session, t->toc_entry->track_no, 0); } void isoburn_toc_disc_free(struct isoburn_toc_disc *d) { if(d->disc!=NULL) burn_disc_free(d->disc); isoburn_toc_destroy_arrays(d, 0); free((char *) d); }