Reading emulated toc info from overwriteable media, new API isoburn_toc_*()

This commit is contained in:
Thomas Schmitt 2008-05-07 17:54:55 +00:00
parent e572e50cae
commit f1dacbfaee
4 changed files with 527 additions and 1 deletions

View File

@ -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(lba<image_size) {
ret= isoburn_read_iso_head(d, lba, &track_blocks, NULL, 0);
if(ret<=0) {
if(session_count>0) {
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; i<session_count; i++) {
o->sessions[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; i<track_count; i++) {
o->tracks[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; i<session_count; i++) {
toc_disc->sessions[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; i<session_count; i++) {
tracks = burn_session_get_tracks(s[i], &num_tracks);
track_count+= num_tracks;
}
if(session_count<=0 || track_count<=0)
goto failure;
ret= isoburn_toc_new_arrays(toc_disc, session_count, track_count, 0);
if(ret<=0)
goto failure;
track_count= 0;
for(i= 0; i<session_count; i++) {
tracks = burn_session_get_tracks(s[i], &num_tracks);
toc_disc->sessions[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; j<num_tracks; j++) {
toc_disc->tracks[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; i<s->track_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);
}

View File

@ -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 */

View File

@ -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);
/* ----------------------------------------------------------------------- */
/*

View File

@ -1 +1 @@
#define Xorriso_timestamP "2008.05.07.071427"
#define Xorriso_timestamP "2008.05.07.175508"