From 7f1b8b07a6adfefbba7f66775c1a2ed8700a85de Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Thu, 8 May 2008 14:10:43 +0000 Subject: [PATCH] Try to read header chain from alleged -ROM media (e.g. DVD+RW in -ROM drive) --- libisoburn/burn_wrap.c | 143 ++++++++++++++++++++++++++++-------- libisoburn/isoburn.h | 13 ++++ libisoburn/libisoburn.h | 4 + xorriso/xorriso_timestamp.h | 2 +- 4 files changed, 130 insertions(+), 32 deletions(-) diff --git a/libisoburn/burn_wrap.c b/libisoburn/burn_wrap.c index 91f6a214..0fb808a6 100644 --- a/libisoburn/burn_wrap.c +++ b/libisoburn/burn_wrap.c @@ -241,16 +241,25 @@ int isoburn_is_intermediate_dvd_rw(struct burn_drive *d, int flag) /** Examines the media and sets appropriate emulation if needed. @param flag bit0= pretent blank on overwriteable media + bit3= if the drive reports a -ROM profile then try to read + table of content by scanning for ISO image headers. */ static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d, int flag) { - int ret, lba, nwa; + int ret, lba, nwa, profile, readonly= 0; struct burn_multi_caps *caps= NULL; + char profile_name[80]; + profile_name[0]= 0; + ret= burn_disc_get_profile(d, &profile, profile_name); + if(ret<=0) + profile= 0x00; 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; + if(ret==0) + readonly= 1; ret= isoburn_new(o, 0); if(ret<=0) goto ex; @@ -286,10 +295,27 @@ static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d, goto ex; } } + } else { - /* >>> recognize unsuitable media (but allow read-only media) */; + /* >>> recognize unsuitable media (but allow read-only media) */; + if(readonly) { + /* This might be overwriteable media in a -ROM drive */ + ret= isoburn_emulate_toc(d, 1); + if(ret<0) + goto ex; + if(ret==0 && profile !=0x08 && (flag&8)) { + /* This might also be multi-session media which do not + get shown with a decent TOC. + CD-R TOC (profile 0x08) can be trusted. Others not. + */ + /* do a scan search of ISO headers */ + ret= isoburn_emulate_toc(d, 1|2); + if(ret<0) + goto ex; + } + } #ifdef Hardcoded_cd_rW (*o)->nwa= Hardcoded_cd_rw_nwA; #else @@ -312,6 +338,10 @@ ex: bit1= regard overwriteable media as blank bit2= if the drive is a regular disk file: truncate it to the write start address + bit3= if the drive reports a -ROM profile then try to read + table of content by scanning for ISO image headers. + (depending on media type and drive state this might + help or it might make the resulting toc even worse) */ int isoburn_drive_aquire(struct burn_drive_info *drive_infos[], char *adr, int flag) @@ -333,7 +363,8 @@ int isoburn_drive_aquire(struct burn_drive_info *drive_infos[], if(ret<=0) goto ex; drive_grabbed= 1; - ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, !!(flag&2)); + ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, + (flag&8) | !!(flag&2)); if(ret<=0) goto ex; @@ -925,31 +956,24 @@ int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno, } -/* API - @param flag bit0-7: info return mode - 0= do not return anything in info (do not even touch it) - 1= return volume id +/* @param flag bit0-7: info return mode + 0= do not return anything in info (do not even touch it) + 1= return volume id + bit14= -reserved - + bit15= -reserved- @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) +int isoburn_read_iso_head_parse(struct burn_drive *d, unsigned char *data, + int *image_blocks, char *info, int flag) { - unsigned char buffer[64*1024], *data; - int ret, i, info_mode; - off_t data_count; + int i, info_mode; - *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); + /* believe so */ *image_blocks= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24); info_mode= flag&255; @@ -971,11 +995,53 @@ int isoburn_read_iso_head(struct burn_drive *d, int lba, } return(1); } - + +/* API + @param flag bit0-7: info return mode + 0= do not return anything in info (do not even touch it) + 1= return volume id + bit14= check both half buffers (not only second) + return 2 if found in first block + bit15= return-1 on read error + @return 1 seems to be a valid ISO image , 2 found in first half buffer, + 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]; + int ret; + 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(-1*!!(flag&(1<<15))); + + if(flag&(1<<14)) { + ret= isoburn_read_iso_head_parse(d, buffer, image_blocks, info, + flag&255); + if(ret<0) + return(ret); + if(ret>0) + return(2); + } + ret= isoburn_read_iso_head_parse(d, buffer+32*1024, image_blocks, info, + flag&255); + return(ret); +} + + +/* @param flag bit0= allow unemulated media + bit1= free scanning without enclosing LBA-0-header + @return -1 severe error, 0= no neat header chain, 1= credible chain read +*/ int isoburn_emulate_toc(struct burn_drive *d, int flag) { - int ret, image_size= 0, lba, track_blocks, session_count= 0; + int ret, image_size= 0, lba, track_blocks, session_count= 0, read_flag= 0; + int scan_start= 0; struct isoburn *o; struct isoburn_toc_entry *item; char msg[160]; @@ -986,20 +1052,32 @@ int isoburn_emulate_toc(struct burn_drive *d, int flag) return(-1); if(o==NULL) return(-1); - if(o->emulation_mode<=0) + if(o->emulation_mode<=0 && !(flag&1)) 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)<<14); + ret= isoburn_read_iso_head(d, lba, &track_blocks, NULL, read_flag); if(ret<=0) { if(session_count>0) { + if(flag&2) { + if(ret==0) { + /* try at next 64 k block (check both 32 k halves) */ + lba+= 32; + if(lba-scan_start <= Libisoburn_toc_scan_max_gaP) + continue; + } + break; + } sprintf(msg, "Chain of ISO session headers broken at #%d, LBA %ds", session_count+1, lba); @@ -1007,6 +1085,8 @@ int isoburn_emulate_toc(struct burn_drive *d, int flag) } {ret= 0; goto failure;} } + if(ret==2) /* ISO header was found in first half block */ + lba-= 16; ret= isoburn_toc_entry_new(&item, o->toc, 0); if(ret<=0) { burn_msgs_submit(0x00060000, @@ -1025,6 +1105,7 @@ int isoburn_emulate_toc(struct burn_drive *d, int flag) lba+= track_blocks; if(lba % Libisoburn_nwa_alignemenT) lba+= Libisoburn_nwa_alignemenT - (lba % Libisoburn_nwa_alignemenT); + scan_start= lba; } sprintf(msg, "Chain of ISO session headers yielded %d sessions", session_count); @@ -1110,7 +1191,7 @@ struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d) /* is the media emulated multi-session ? */ ret= isoburn_find_emulator(&o, d, 0); - if(ret<=0) + if(ret<0) goto libburn; if(o->toc==NULL) goto libburn; diff --git a/libisoburn/isoburn.h b/libisoburn/isoburn.h index 66e2ec28..11d1cbe9 100644 --- a/libisoburn/isoburn.h +++ b/libisoburn/isoburn.h @@ -351,6 +351,19 @@ struct isoburn_imgen_opts { */ #define Libisoburn_nwa_alignemenT 32 + +/* Alignment for outer session scanning with -ROM drives. + (E.g. my DVD-ROM drive shows any DVD type as 0x10 "DVD-ROM" with + more or less false capacity and TOC.) +*/ +#define Libisoburn_toc_scan_alignemenT 16 + +/* Maximum gap to be bridged during a outer TOC scan. Gaps appear between the + end of a session and the start of the next session. +*/ +#define Libisoburn_toc_scan_max_gaP 8192 + + /* Size of target_iso_head which is to be written during isoburn_activate_session() */ diff --git a/libisoburn/libisoburn.h b/libisoburn/libisoburn.h index 122db931..12950fdf 100644 --- a/libisoburn/libisoburn.h +++ b/libisoburn/libisoburn.h @@ -330,6 +330,10 @@ int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[], bit1= regard overwriteable media as blank bit2= if the drive is a regular disk file: truncate it to the write start address + bit3= if the drive reports a read-only profile try to read + table of content by scanning for ISO image headers. + (depending on media type and drive this might + help or it might make the resulting toc even worse) @return 1 = success , 0 = drive not found , <0 = other error */ int isoburn_drive_aquire(struct burn_drive_info *drive_infos[], diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 64662d03..fa510ec4 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.05.07.214442" +#define Xorriso_timestamP "2008.05.08.141054"