Enabled multi-session with partition offset

This commit is contained in:
Thomas Schmitt 2010-09-10 17:10:03 +00:00
parent 5af8ad46f4
commit d54efd4bc2
6 changed files with 215 additions and 64 deletions

View File

@ -1192,7 +1192,7 @@ int isoburn_emulate_toc(struct burn_drive *d, int flag)
ret= isoburn_read_iso_head(d, lba, &image_size, NULL, 0);
if(ret<=0)
{ret= 0; goto failure;}
lba= Libisoburn_overwriteable_starT;
lba= o->target_iso_head_size / 2048;
with_enclosure= 1;
if((flag & 16) && o->emulation_mode == 1) {
ret= 1;
@ -1219,7 +1219,7 @@ int isoburn_emulate_toc(struct burn_drive *d, int flag)
/* growisofs aligns to 16 rather than 32. Overwriteable TOC emulation
relies on not accidentially seeing inter-session trash data.
But one can safely access 16 blocks earlier because a xorriso header
would have overwritten with the unused 16 blocks at its start.
would have been overwritten with the unused 16 blocks at its start.
If libisoburn alignment would increase, then this would not be
possible any more.
*/

View File

@ -115,7 +115,7 @@ struct isoburn *isoburn_list_start= NULL;
int isoburn_new(struct isoburn **objpt, int flag)
{
struct isoburn *o;
int i, ret;
int ret;
*objpt= o= (struct isoburn *) malloc(sizeof(struct isoburn));
if(o==NULL) {
@ -137,8 +137,9 @@ int isoburn_new(struct isoburn **objpt, int flag)
o->fabricated_disc_status= BURN_DISC_UNREADY;
o->toc= NULL;
o->wrote_well= -1;
for(i=0;i<Libisoburn_target_head_sizE;i++)
o->target_iso_head[i]= 0;
o->loaded_partition_offset= 0;
o->target_iso_head_size= Libisoburn_target_head_sizE;
o->target_iso_head= NULL;
o->image= NULL;
o->iso_data_source= NULL;
o->read_pacifier= NULL;
@ -148,9 +149,15 @@ int isoburn_new(struct isoburn **objpt, int flag)
o->msgs_submit_flag= 0;
o->prev= NULL;
o->next= NULL;
o->target_iso_head= calloc(1, o->target_iso_head_size);
if(o->target_iso_head == NULL) {
isoburn_report_iso_error(ISO_OUT_OF_MEM, "Cannot allocate overwrite buffer",
0, "FATAL", 0);
goto failed;
}
ret= iso_image_new("ISOIMAGE", &o->image);
if(ret<0) {
isoburn_report_iso_error(ret, "Cannot create image", 0, "FATAL", 0);
isoburn_report_iso_error(ret, "Cannot create image object", 0, "FATAL", 0);
goto failed;
}
isoburn_link(o, isoburn_list_start, 1);
@ -188,6 +195,8 @@ int isoburn_destroy(struct isoburn **objpt, int flag)
burn_source_free(o->iso_source);
if(o->iso_data_source!=NULL)
iso_data_source_unref(o->iso_data_source);
if(o->target_iso_head != NULL)
free(o->target_iso_head);
free((char *) o);
*objpt= NULL;
return(1);
@ -346,6 +355,37 @@ int isoburn_msgs_submit(struct isoburn *o, int error_code, char msg_text[],
}
/* TWINTREE:
Check whether size of target_iso_head matches partition offset.
Eventually adjust size.
*/
int isoburn_adjust_target_iso_head(struct isoburn *o,
uint32_t offst, int flag)
{
uint8_t *new_buf;
uint32_t new_size;
if(o->target_iso_head_size == Libisoburn_target_head_sizE + 2048 * offst)
return(1);
new_size= Libisoburn_target_head_sizE + 2048 * offst;
new_buf= calloc(1, new_size);
if(new_buf == NULL) {
isoburn_msgs_submit(o, 0x00060000,
"Cannot re-allocate overwrite buffer", 0, "FATAL", 0);
return(-1);
}
memcpy(new_buf, o->target_iso_head,
o->target_iso_head_size < new_size ? o->target_iso_head_size : new_size);
free(o->target_iso_head);
o->target_iso_head= new_buf;
o->target_iso_head_size= new_size;
if(o->nwa == o->zero_nwa)
o->nwa= Libisoburn_overwriteable_starT + offst;
o->zero_nwa= Libisoburn_overwriteable_starT + offst;
return(1);
}
/* @param flag bit0= modifying rather than growing
bit1= prepare for early release of input drive:
wait until input and then disable image data source
@ -458,10 +498,17 @@ int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
opts->vol_expiration_time, opts->vol_effective_time,
opts->vol_uuid);
ret= isoburn_adjust_target_iso_head(out_o, opts->partition_offset, 0);
if(ret <= 0)
{ret= -1; goto ex;}
iso_write_opts_set_overwrite_buf(wopts,
nwa>0 ? out_o->target_iso_head : NULL);
if(opts->no_emul_toc) {
if(out_o->nwa == out_o->zero_nwa &&
out_o->zero_nwa == Libisoburn_overwriteable_starT &&
out_o->emulation_mode == 1) {
out_o->zero_nwa == Libisoburn_overwriteable_starT
+ opts->partition_offset
&& out_o->emulation_mode == 1) {
out_o->nwa= 0;
out_o->zero_nwa= 0;
out_o->min_start_byte= 0;
@ -477,41 +524,9 @@ int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
}
iso_write_opts_set_ms_block(wopts, nwa);
iso_write_opts_set_appendable(wopts, !new_img);
iso_write_opts_set_overwrite_buf(wopts,
nwa>0 ? out_o->target_iso_head : NULL);
if (opts->partition_offset > 0) {
if (nwa > 0) {
/* >>> refuse because for now this works only for single session with
no_emul_toc
<<< to be removed when multi session stuff is fully ready
*/
isoburn_msgs_submit(in_o, 0x00060000,
"Programming error: non-zero NWA combined with partition offset",
0, "FATAL", 0);
{ret= -4; goto ex;}
}
iso_write_opts_set_part_offset(wopts, opts->partition_offset,
opts->partition_secs_per_head,
opts->partition_heads_per_cyl);
}
#ifdef Libisoburn_partition_offseT
#if Libisoburn_partition_offseT >= 16
else {
/* <<< For preliminary testing of emulated TOC and partition offset.
Problem is that only this macro can prepare the overwrite buffer
for partition offset yet. Emulated TOC does not work yet.
*/
iso_write_opts_set_part_offset(wopts,
(uint32_t) Libisoburn_partition_offseT,
0, 0);
}
#endif
#endif
ret = iso_image_create_burn_source(in_o->image, wopts, &wsrc);
if (ret < 0) {

View File

@ -36,20 +36,15 @@ int isoburn_toc_entry_new(struct isoburn_toc_entry **objpt,
int isoburn_toc_entry_destroy(struct isoburn_toc_entry **o, int flag);
/* >>> TWINTREE : provisory test of partition offset with emulated TOC.
.target_iso_head must become dynamically allocated
#define Libisoburn_partition_offseT 16
/* Minimal size of target_iso_head which is to be written during
isoburn_activate_session().
TWINTREE:
Within this size there is everything that is needed for image access with
no partition offset. The actual target_iso_head buffer must be larger by
the evential partition offset.
*/
/* Size of target_iso_head which is to be written during
isoburn_activate_session()
*/
#ifdef Libisoburn_partition_offseT
#define Libisoburn_target_head_sizE (32*2048 +Libisoburn_partition_offseT*2048)
#else
#define Libisoburn_target_head_sizE (32*2048)
#endif
struct isoburn {
@ -114,9 +109,14 @@ struct isoburn {
int wrote_well;
/* Buffered ISO head from media (should that become part of
ecma119_read_opts ?) */
uint8_t target_iso_head[Libisoburn_target_head_sizE];
/* ISO head buffer to be filled by write run */
int target_iso_head_size;
uint8_t *target_iso_head;
/* The 2k offset which was read from a loaded image.
*/
uint32_t loaded_partition_offset;
/* Libisofs image context */
IsoImage *image;
@ -253,6 +253,13 @@ isoburn_data_source_new(struct burn_drive *d);
int isoburn_data_source_shutdown(IsoDataSource *src, int flag);
/** TWINTREE:
Check whether size of target_iso_head matches offset.
Eventually adjust size.
*/
int isoburn_adjust_target_iso_head(struct isoburn *o,
uint32_t offst, int flag);
/**
* Options for image reading.
(Comments here may be outdated. API getter/setter function descriptions
@ -576,6 +583,10 @@ struct isoburn_imgen_opts {
written by random access before they were written sequentially.
In this case, no copy of the session 1 header is maintained and no TOC
will be possible. Thus writing begins sequentially at LBA 0.
TWINTREE:
This macro gives the minimal size of an image header. It has to be
enlarged by the eventual partition offset.
*/
#define Libisoburn_overwriteable_starT \
((off_t) (Libisoburn_target_head_sizE/2048))

View File

@ -32,8 +32,8 @@
#endif /* Xorriso_standalonE */
#include "isoburn.h"
#include "libisoburn.h"
#include "isoburn.h"
#define BP(a,b) [(b) - (a) + 1]
@ -299,12 +299,111 @@ int isoburn_activate_session(struct burn_drive *drive)
return 1;
ret = burn_random_access_write(drive, (off_t) 0, (char*)o->target_iso_head,
Libisoburn_target_head_sizE, 1);
o->target_iso_head_size, 1);
return ret;
}
/** TWINTREE:
API @since 0.6.2
*/
int isoburn_get_img_partition_offset(struct burn_drive *drive,
uint32_t *block_offset_2k)
{
int ret;
struct isoburn *o;
ret = isoburn_find_emulator(&o, drive, 0);
if(ret < 0 || o == NULL)
return -1;
*block_offset_2k= o->loaded_partition_offset;
if(o->loaded_partition_offset == 0)
return(0);
if(o->target_iso_head_size == (off_t) Libisoburn_target_head_sizE
+ (off_t) 2048 * (off_t) o->loaded_partition_offset)
return(1);
return(2);
}
/* TWINTREE:
Check for MBR signature and a first partition that starts at a 2k block
and ends where the image ends.
If not too large or too small, accept its start as partition offset.
*/
static int isoburn_inspect_partition(struct isoburn *o, uint32_t img_size,
int flag)
{
uint8_t *mbr, *part, buf[2048];
uint32_t offst, numsec;
struct ecma119_pri_vol_desc *pvm;
off_t data_count;
int ret;
char msg[160];
static int max_offst= 512 - 32;
mbr= o->target_iso_head;
part= mbr + 446;
if(mbr[510] != 0x55 || mbr[511] != 0xAA)
return(2); /* not an MBR */
/* Does the first partition entry look credible ? */
if(part[0] != 0x80 && part[0] != 0x00)
return(2); /* Invalid partition status */
if(part[1] == 0 && part[2] == 0 && part[3] == 0)
return(2); /* Zero C/H/S start address */
/* Does it match the normal ISO image ? */
offst= iso_read_lsb(part + 8, 4);
numsec= iso_read_lsb(part + 12, 4);
if(offst < 64)
return(2); /* Zero or unusably small partition start */
if((offst % 4) || (numsec % 4))
return(2); /* Not aligned to 2k */
if(numsec < 72)
return(2); /* No room for volume descriptors */
offst/= 4;
numsec/= 4;
if(offst + numsec != img_size)
return(2); /* Partition end does not match image end */
/* Is there a PVD at the partition start ? */
ret = burn_read_data(o->drive, (off_t) (offst + 16) * (off_t) 2048,
(char*) buf, 2048, &data_count, 2);
if(ret <= 0)
return(2);
pvm = (struct ecma119_pri_vol_desc *) buf;
if (strncmp((char*) pvm->std_identifier, "CD001", 5) != 0)
return(2); /* not a PVD */
if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
|| pvm->file_structure_version[0] != 1 )
return(2); /* failed sanity check */
if(iso_read_lsb(pvm->vol_space_size, 4) + offst != img_size)
return(2); /* Image ends do not match */
/* Now it is credible. Not yet clear is whether it is acceptable. */
o->loaded_partition_offset= offst;
/* If the partition start is too large: Report but do not accept. */
if(offst > max_offst) { /* Not more than 1 MB of .target_iso_head */
sprintf(msg,
"Detected partition offset of %.f blocks. Maximum for load buffer is %d",
(double) offst, max_offst);
isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "WARNING", 0);
return(3);
}
/* Accept partition start and adjust buffer size */
ret= isoburn_adjust_target_iso_head(o, offst, 0);
if(ret <= 0)
return(ret);
return(1);
}
/** Initialize the emulation of multi-session on random access media.
The need for emulation is confirmed already.
@param o A freshly created isoburn object. isoburn_create_data_source() was
@ -337,8 +436,8 @@ int isoburn_start_emulation(struct isoburn *o, int flag)
if (capacity > 0 || role == 2) {
/* Might be a block device on a system where libburn cannot determine its
size. Try to read anyway. */
memset(o->target_iso_head, 0, Libisoburn_target_head_sizE);
to_read = Libisoburn_target_head_sizE;
to_read = o->target_iso_head_size;
memset(o->target_iso_head, 0, to_read);
if(capacity > 0 && (off_t) capacity * (off_t) 2048 < to_read)
to_read = (off_t) capacity * (off_t) 2048;
ret = burn_read_data(drive, (off_t) 0, (char*)o->target_iso_head,
@ -370,7 +469,7 @@ int isoburn_start_emulation(struct isoburn *o, int flag)
pvm = (struct ecma119_pri_vol_desc *)(o->target_iso_head + 16 * 2048);
if (!strncmp((char*)pvm->std_identifier, "CD001", 5)) {
if (strncmp((char*)pvm->std_identifier, "CD001", 5) == 0) {
off_t size;
/* sanity check */
@ -383,6 +482,9 @@ int isoburn_start_emulation(struct isoburn *o, int flag)
/* ok, PVM found, set size */
size = (off_t) iso_read_lsb(pvm->vol_space_size, 4);
ret= isoburn_inspect_partition(o, (uint32_t) size, 0);
if (ret <= 0)
return ret;
size *= (off_t) 2048; /* block size in bytes */
isoburn_set_start_byte(o, size, 0);
o->fabricated_disc_status= BURN_DISC_APPENDABLE;
@ -395,6 +497,7 @@ int isoburn_start_emulation(struct isoburn *o, int flag)
/* treat any disc in an unknown format as full */
o->fabricated_disc_status= BURN_DISC_FULL;
}
return 1;
}

View File

@ -1361,6 +1361,24 @@ int isoburn_set_read_pacifier(struct burn_drive *drive,
int (*read_pacifier)(IsoImage*, IsoFileSource*),
void *app_handle);
/** TWINTREE:
Inquire the partition offset of the loaded image. The first 512 bytes of
the image get examined whether they bear an MBR signature and a first
partition table entry which matches the size of the image. In this case
the start address is recorded as partition offset and internal buffers
get adjusted.
See also isoburn_igopt_set_part_offset().
@since 0.6.2
@param drive The drive with the loaded image
@param block_offset_2k returns the recognized partition offset
@return <0 = error
0 = no partition offset recognized
1 = acceptable non-zero offset, buffers are adjusted
2 = offset is credible but not acceptable for buffer size
*/
int isoburn_get_img_partition_offset(struct burn_drive *drive,
uint32_t *block_offset_2k);
/** Set the IsoImage to be used with a drive. This eventually releases
the reference to the old IsoImage attached to the drive.
@ -1659,3 +1677,7 @@ void isoburn_finish(void);
int isoburn_needs_emulation(struct burn_drive *d);
/* ---------------------------- Test area ----------------------------- */
/* no tests active, currently */

View File

@ -1 +1 @@
#define Xorriso_timestamP "2010.09.06.103347"
#define Xorriso_timestamP "2010.09.10.170925"