From e9171b513380f9ecc3f72dac8edb224a0e8c5918 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Wed, 7 May 2008 17:54:55 +0000 Subject: [PATCH] Reading emulated toc info from overwriteable media, new API isoburn_toc_*() --- libisoburn/burn_wrap.c | 378 ++++++++++++++++++++++++++++++++++++ libisoburn/isoburn.h | 34 ++++ libisoburn/libisoburn.h | 114 +++++++++++ xorriso/xorriso_timestamp.h | 2 +- 4 files changed, 527 insertions(+), 1 deletion(-) diff --git a/libisoburn/burn_wrap.c b/libisoburn/burn_wrap.c index 8b180ad3..8453c1f8 100644 --- a/libisoburn/burn_wrap.c +++ b/libisoburn/burn_wrap.c @@ -50,6 +50,9 @@ 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; @@ -276,6 +279,12 @@ static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d, (*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 { @@ -915,3 +924,372 @@ int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno, return(ret); } + +/* @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 seems not to be ISO, <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; + + 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 count= 0; + + if(disc==NULL) + return(0); + if(disc->toc!=NULL) { + for(t= disc->toc; t!=NULL; t= t->next) + count+= t->track_blocks; + } else if(disc->disc!=NULL) + count= burn_disc_get_sectors(disc->disc); + return(count); +} + + +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); +} + diff --git a/libisoburn/isoburn.h b/libisoburn/isoburn.h index 859cfe93..66e2ec28 100644 --- a/libisoburn/isoburn.h +++ b/libisoburn/isoburn.h @@ -25,6 +25,13 @@ struct isoburn_toc_entry { struct isoburn_toc_entry *next; }; +int isoburn_toc_entry_new(struct isoburn_toc_entry **objpt, + struct isoburn_toc_entry *boss, int flag); + +/* @param flag bit0= delete all subordinates too +*/ +int isoburn_toc_entry_destroy(struct isoburn_toc_entry **o, int flag); + struct isoburn { @@ -366,6 +373,33 @@ struct isoburn_imgen_opts { ((off_t) (Libisoburn_target_head_sizE/2048)) +/* Wrappers for emulation of TOC on overwriteable media */ + +struct isoburn_toc_track { + /* Either track or toc_entry are supposed to be NULL */ + struct burn_track *track; + struct isoburn_toc_entry *toc_entry; +}; + +struct isoburn_toc_session { + /* Either session or tracks and toc_entry are supposed to be NULL */ + struct burn_session *session; + struct isoburn_toc_track **track_pointers; + int track_count; + struct isoburn_toc_entry *toc_entry; +}; + +struct isoburn_toc_disc { + /* Either disc or sessions and toc are supposed to be NULL */ + struct burn_disc *disc; + struct isoburn_toc_session *sessions; /* storage array */ + struct isoburn_toc_session **session_pointers; /* storage array */ + struct isoburn_toc_track *tracks; /* storage array */ + struct isoburn_toc_track **track_pointers; /* storage array */ + int session_count; + int track_count; + struct isoburn_toc_entry *toc; +}; #endif /* Isoburn_includeD */ diff --git a/libisoburn/libisoburn.h b/libisoburn/libisoburn.h index c46ef5fd..ab6756ee 100644 --- a/libisoburn/libisoburn.h +++ b/libisoburn/libisoburn.h @@ -381,6 +381,120 @@ int isoburn_disc_erasable(struct burn_drive *d); void isoburn_disc_erase(struct burn_drive *drive, int fast); +/* ----------------------------------------------------------------------- */ +/* + + Wrappers for emulation of TOC on overwriteable media + + Media which match the overwriteable usage model lack of a history of sessions + and tracks. libburn will not even hand out a burn_disc object for them and + always declare them blank. libisoburn checks for a valid ISO filesystem + header at LBA 0 and eventually declares them appendable. + Nevertheless one can only determine an upper limit of the size of the overall + image (by isoburn_get_min_start_byte()) but not a list of stored sessions + and their LBAs, as it is possible with true multi-session media. + + The following wrappers add the capability to obtain a session and track TOC + from emulated multi-session images on overwriteables if the first session + was written by libisoburn-0.1.6 or later (i.e. with a header copy at LBA 32). + + Be aware that the structs emitted by these isoburn calls are not compatible + with the libburn structs. I.e. you may use them only with isoburn_toc_* + calls. + isoburn_toc_disc needs to be freed after use. isoburn_toc_session and + isoburn_toc_track vanish together with their isoburn_toc_disc. +*/ + +/* Opaque handles to media, session, track */ +struct isoburn_toc_disc; +struct isoburn_toc_session; +struct isoburn_toc_track; + + +/** Obtain a master handle for the table of content. + This handle governs allocated resources which have to be released by + isoburn_toc_disc_free() when no longer needed. + Wrapper for: burn_drive_get_disc() + @since 0.1.6 + @param drive The drive with the media to inspect + @return NULL in case there is no content info, else it is a valid handle +*/ +struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d); + + +/** Tell the number of 2048 byte blocks covered by the table of content. + Wrapper for: burn_disc_get_sectors() + @since 0.1.6 + @param disc The master handle of the media + @return number of blocks, <=0 indicates unknown or unreadable state +*/ +int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc); + + +/** Get the array of session handles from the table of content. + Wrapper for: burn_disc_get_sessions() + @since 0.1.6 + @param disc The master handle of the media + @param num returns the number of sessions in the array + @return the address of the array of session handles +*/ +struct isoburn_toc_session **isoburn_toc_disc_get_sessions( + struct isoburn_toc_disc *disc, int *num); + + +/** Tell the number of 2048 byte blocks covered by a particular session. + Wrapper for: burn_session_get_sectors() + @since 0.1.6 + @param s The session handle + @return number of blocks, <=0 indicates unknown or unreadable state +*/ +int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s); + + +/** Obtain a copy of the entry which describes the end of a particular session. + Wrapper for: burn_session_get_leadout_entry() + @since 0.1.6 + @param s The session handle + @param entry A pointer to memory provided by the caller. It will be filled + with info according to struct burn_toc_entry as defined + in libburn.h +*/ +void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s, + struct burn_toc_entry *entry); + + +/** Get the array of track handles from a particular session. + Wrapper for: burn_session_get_tracks() + @since 0.1.6 + @param s The session handle + @param num returns the number of tracks in the array + @return the address of the array of track handles +*/ +struct isoburn_toc_track **isoburn_toc_session_get_tracks( + struct isoburn_toc_session *s, int *num); + + +/** Obtain a copy of the entry which describes a particular itrack. + Wrapper for: burn_track_get_entry() + @since 0.1.6 + @param s The track handle + @param entry A pointer to memory provided by the caller. It will be filled + with info according to struct burn_toc_entry as defined + in libburn.h +*/ +void isoburn_toc_track_get_entry(struct isoburn_toc_track *t, + struct burn_toc_entry *entry); + + +/** Release the memory associated with a master handle of media. + The handle is invalid afterwards and may not be used any more. + Wrapper for: burn_disc_free() + @since 0.1.6 + @param disc The master handle of the media +*/ +void isoburn_toc_disc_free(struct isoburn_toc_disc *disc); + + /* ----------------------------------------------------------------------- */ /* diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 8eaf7907..ca781ef3 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.05.07.071427" +#define Xorriso_timestamP "2008.05.07.175508"