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