New API function isoburn_prepare_blind_grow() for -as mkisofs -multi

This commit is contained in:
Thomas Schmitt 2008-07-05 13:25:06 +00:00
parent 73a02c1a07
commit 161bf5748c
7 changed files with 224 additions and 44 deletions

View File

@ -625,6 +625,23 @@ int isoburn_disc_track_lba_nwa(struct burn_drive *d,
} }
int isoburn_get_msc2(struct isoburn *o,
struct burn_write_opts *opts, int *msc2, int flag)
{
int ret, lba, nwa;
if(o->fabricated_msc2>=0)
*msc2= o->fabricated_msc2;
else {
ret= isoburn_disc_track_lba_nwa(o->drive, opts, 0, &lba, &nwa);
if(ret<=0)
return(ret);
*msc2= nwa;
}
return(1);
}
void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
{ {
int ret; int ret;

View File

@ -85,6 +85,19 @@ int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
icd = (struct isoburn_cached_drive *) src->data; icd = (struct isoburn_cached_drive *) src->data;
d = (struct burn_drive*) icd->drive; d = (struct burn_drive*) icd->drive;
if(d == NULL) {
/* This would happen if libisoburn saw output data in the fifo and
performed early drive release and afterwards libisofs still tries
to read data.
That would constitute a bad conceptual problem in libisoburn.
*/
isoburn_msgs_submit(NULL, 0x00060000,
"Programming error: Drive released while libisofs still attempts to read",
0, "FATAL", 0);
return ISO_ASSERT_FAILURE;
}
tiles = (struct isoburn_cache_tile *) icd->tiles; tiles = (struct isoburn_cache_tile *) icd->tiles;
aligned_lba= lba & ~(Libisoburn_tile_blockS - 1); aligned_lba= lba & ~(Libisoburn_tile_blockS - 1);
@ -189,6 +202,19 @@ static void ds_free_data(IsoDataSource *src)
src->data= NULL; src->data= NULL;
} }
int isoburn_data_source_shutdown(IsoDataSource *src, int flag)
{
struct isoburn_cached_drive *icd;
if(src==NULL)
return(0);
icd= (struct isoburn_cached_drive *) src->data;
icd->drive= NULL;
return(1);
}
IsoDataSource *isoburn_data_source_new(struct burn_drive *d) IsoDataSource *isoburn_data_source_new(struct burn_drive *d)
{ {
IsoDataSource *ret; IsoDataSource *ret;

View File

@ -119,6 +119,7 @@ int isoburn_new(struct isoburn **objpt, int flag)
o->drive= NULL; o->drive= NULL;
o->emulation_mode= 0; o->emulation_mode= 0;
o->fabricated_msc1= -1; o->fabricated_msc1= -1;
o->fabricated_msc2= -1;
o->zero_nwa= Libisoburn_overwriteable_starT; o->zero_nwa= Libisoburn_overwriteable_starT;
o->min_start_byte= o->zero_nwa * 2048; o->min_start_byte= o->zero_nwa * 2048;
o->nwa= o->zero_nwa; o->nwa= o->zero_nwa;
@ -130,6 +131,7 @@ int isoburn_new(struct isoburn **objpt, int flag)
for(i=0;i<Libisoburn_target_head_sizE;i++) for(i=0;i<Libisoburn_target_head_sizE;i++)
o->target_iso_head[i]= 0; o->target_iso_head[i]= 0;
o->image= NULL; o->image= NULL;
o->iso_data_source= NULL;
o->read_pacifier= NULL; o->read_pacifier= NULL;
o->read_pacifier_handle= NULL; o->read_pacifier_handle= NULL;
o->msgs_submit= NULL; o->msgs_submit= NULL;
@ -175,7 +177,8 @@ int isoburn_destroy(struct isoburn **objpt, int flag)
isoburn_toc_entry_destroy(&(o->toc), 1); /* all */ isoburn_toc_entry_destroy(&(o->toc), 1); /* all */
if(o->iso_source!=NULL) if(o->iso_source!=NULL)
burn_source_free(o->iso_source); burn_source_free(o->iso_source);
if(o->iso_data_source!=NULL)
iso_data_source_unref(o->iso_data_source);
free((char *) o); free((char *) o);
*objpt= NULL; *objpt= NULL;
return(1); return(1);
@ -334,10 +337,14 @@ int isoburn_msgs_submit(struct isoburn *o, int error_code, char msg_text[],
} }
/* @param flag bit0= modifying rather than growing
bit1= prepare for early release of input drive:
wait until input and then disable image data source
*/
static static
int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d, int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
struct burn_disc **disc, struct burn_disc **disc,
struct isoburn_imgen_opts *opts, int new_img) struct isoburn_imgen_opts *opts, int flag)
{ {
struct burn_source *wsrc; struct burn_source *wsrc;
struct burn_session *session; struct burn_session *session;
@ -345,7 +352,18 @@ int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
struct isoburn *in_o, *out_o; struct isoburn *in_o, *out_o;
IsoWriteOpts *wopts= NULL; IsoWriteOpts *wopts= NULL;
enum burn_disc_status state; enum burn_disc_status state;
int ret, fifo_chunks, lba, nwa; int ret, fifo_chunks, nwa, i, new_img, early_indev_release;
size_t buffer_size= 0, buffer_free= 0;
char msg[160];
new_img= flag&1;
early_indev_release= flag&2;
if(new_img && early_indev_release) {
isoburn_msgs_submit(in_o, 0x00060000,
"Programming error: Wrong session setup: new_img && early_indev_release",
0, "FATAL", 0);
{ret= -4; goto ex;}
}
ret= isoburn_find_emulator(&in_o, in_d, 0); ret= isoburn_find_emulator(&in_o, in_d, 0);
if(ret<0 || in_o==NULL) if(ret<0 || in_o==NULL)
@ -405,19 +423,12 @@ int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
iso_write_opts_set_output_charset(wopts, opts->output_charset); iso_write_opts_set_output_charset(wopts, opts->output_charset);
iso_write_opts_set_fifo_size(wopts, fifo_chunks); iso_write_opts_set_fifo_size(wopts, fifo_chunks);
ret= isoburn_get_msc2(out_o, NULL, &nwa, 0);
ret = isoburn_disc_track_lba_nwa(out_d, NULL, 0, &lba, &nwa);
if (ret != 1) { if (ret != 1) {
isoburn_msgs_submit(out_o, 0x00060000, isoburn_msgs_submit(out_o, 0x00060000,
"Cannot determine next writeable address", 0, "FAILURE", 0); "Cannot determine next writeable address", 0, "FAILURE", 0);
{ret= -3; goto ex;} {ret= -3; goto ex;}
} }
if (nwa == 0 && state == BURN_DISC_APPENDABLE) {
isoburn_msgs_submit(out_o, 0x00060000,
"Encountered 0 as next writeable address of appendable",
0, "FAILURE", 0);
{ret= -4; goto ex;}
}
iso_write_opts_set_ms_block(wopts, nwa); iso_write_opts_set_ms_block(wopts, nwa);
opts->effective_lba= nwa; opts->effective_lba= nwa;
iso_write_opts_set_appendable(wopts, !new_img); iso_write_opts_set_appendable(wopts, !new_img);
@ -429,6 +440,30 @@ int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d,
isoburn_report_iso_error(ret, "Cannot create burn source", 0, "FAILURE", 0); isoburn_report_iso_error(ret, "Cannot create burn source", 0, "FAILURE", 0);
{ret= -1; goto ex;} {ret= -1; goto ex;}
} }
if (early_indev_release) {
for(i= 0; i<300; i++) {
/* <<< ??? */
if((i%30) == 0) {
sprintf(msg, "Waiting for data in fifo since %d seconds", i/30);
isoburn_msgs_submit(in_o, 0x00060000, msg, 0, "DEBUG", 0);
}
usleep(100000);
ret= iso_ring_buffer_get_status(wsrc, &buffer_size, &buffer_free);
if(ret >0 && buffer_size != buffer_free)
break;
}
/* <<< ??? */
sprintf(msg,
"After %.1f seconds: %d bytes of output available (fifo state=%d)",
((double) i+1) / 10.0, (int) (buffer_size - buffer_free), ret);
isoburn_msgs_submit(in_o, 0x00060000, msg, 0, "DEBUG", 0);
if(in_o->iso_data_source!=NULL)
isoburn_data_source_shutdown(in_o->iso_data_source, 0);
}
/* TODO check return values for failure. propertly clean-up on error */ /* TODO check return values for failure. propertly clean-up on error */
@ -474,6 +509,27 @@ int isoburn_prepare_new_image(struct burn_drive *d, struct burn_disc **disc,
} }
/* API since 0.2.2 */
int isoburn_prepare_blind_grow(struct burn_drive *d, struct burn_disc **disc,
struct isoburn_imgen_opts *opts,
struct burn_drive *out_drive, int nwa)
{
int ret;
struct isoburn *o= NULL;
if(nwa >= 0) {
ret= isoburn_find_emulator(&o, out_drive, 0);
if(ret<0 || o==NULL)
return(-1);
o->fabricated_msc2= nwa;
}
ret= isoburn_prepare_disc_aux(d, out_drive, disc, opts, 2);
if (ret<=0)
return ret;
return(1);
}
/* API @since 0.1.0 /* API @since 0.1.0
@param flag bit0= this is a regular end, not an abort @param flag bit0= this is a regular end, not an abort
give up source reference give up source reference

View File

@ -60,6 +60,14 @@ struct isoburn {
*/ */
int fabricated_msc1; int fabricated_msc1;
/* If >= 0, this address is used in isoburn_disc_track_lba_nwa()
as reply parameter nwa.
(The other nwa parameters below apply only to the effective write address
on random access media. msc2 is handed to libisofs but not to libburn.)
*/
int fabricated_msc2;
/* The nwa to be used for a first session on the present kind of overwriteable /* The nwa to be used for a first session on the present kind of overwriteable
media (usually Libisoburn_overwriteable_starT, but might be forced to 0) media (usually Libisoburn_overwriteable_starT, but might be forced to 0)
*/ */
@ -71,6 +79,7 @@ struct isoburn {
/* Aligned start address to be used for processing (counted in blocks) */ /* Aligned start address to be used for processing (counted in blocks) */
int nwa; int nwa;
/* Truncate to .nwa an eventual regular file serving as output drive */ /* Truncate to .nwa an eventual regular file serving as output drive */
int truncate; int truncate;
@ -99,6 +108,10 @@ struct isoburn {
/* Libisofs image context */ /* Libisofs image context */
IsoImage *image; IsoImage *image;
/* The block data source from which the existing image is read.
*/
IsoDataSource *iso_data_source;
/* The burn source which transfers data from libisofs to libburn. /* The burn source which transfers data from libisofs to libburn.
It has its own fifo. It has its own fifo.
*/ */
@ -190,6 +203,19 @@ int isoburn_msgs_submit(struct isoburn *o, int error_code, char msg_text[],
*/ */
int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag); int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag);
/** Obtains the image address offset to be used with image generation.
This is either the (emulated) drive nwa or a value set by
isoburn_prepare_blind_grow().
In any case this is the address to tell to iso_write_opts_set_ms_block().
@param o The isoburn object to be inquired
@param opts If not NULL: write parameters to be set on drive before query
@param msc2 The value to be used with iso_write_opts_set_ms_block()
@param flag unused yet
@return <=0 is failure , >0 success
*/
int isoburn_get_msc2(struct isoburn *o,
struct burn_write_opts *opts, int *msc2, int flag);
/** Get a data source suitable for read from a drive using burn_read_data() /** Get a data source suitable for read from a drive using burn_read_data()
function. function.
@param d drive to read from. Must be grabbed. @param d drive to read from. Must be grabbed.
@ -200,6 +226,19 @@ int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag);
IsoDataSource * IsoDataSource *
isoburn_data_source_new(struct burn_drive *d); isoburn_data_source_new(struct burn_drive *d);
/** Disable read capabilities of a data source which was originally created
by isoburn_data_source_new(). After this any attempt to read will yield
a FATAL programming error event.
This is usually done to allow libburn to release the drive while libisofs
still holds a reference to the data source object. libisofs is not supposed
to use this object for reading any more, nevertheless. The disabled state
of the data source is a safety fence around this daring situation.
@param src The data source to be disabled
@param flag unused yet
@return <=0 is failure , >0 success
*/
int isoburn_data_source_shutdown(IsoDataSource *src, int flag);
/** /**
* Options for image reading. * Options for image reading.

View File

@ -212,6 +212,9 @@ create_blank_image:;
*/ */
ds = isoburn_data_source_new(d); ds = isoburn_data_source_new(d);
if(o->iso_data_source!=NULL)
iso_data_source_unref(o->iso_data_source);
o->iso_data_source= ds;
iso_image_attach_data(o->image, o->read_pacifier_handle, iso_image_attach_data(o->image, o->read_pacifier_handle,
isoburn_idle_free_function); isoburn_idle_free_function);
if(o->read_pacifier_handle==NULL) if(o->read_pacifier_handle==NULL)
@ -221,7 +224,7 @@ create_blank_image:;
ret = iso_image_import(o->image, ds, ropts, &features); ret = iso_image_import(o->image, ds, ropts, &features);
iso_tree_set_report_callback(o->image, NULL); iso_tree_set_report_callback(o->image, NULL);
iso_read_opts_free(ropts); iso_read_opts_free(ropts);
iso_data_source_unref(ds);
if (ret < 0) { if (ret < 0) {
isoburn_report_iso_error(ret, "Cannot import image", 0, "FAILURE", 0); isoburn_report_iso_error(ret, "Cannot import image", 0, "FAILURE", 0);
return ret; return ret;
@ -277,6 +280,8 @@ int isoburn_activate_session(struct burn_drive *drive)
if (o->emulation_mode != 1) if (o->emulation_mode != 1)
return 1; /* don't need to activate session */ return 1; /* don't need to activate session */
if (o->fabricated_msc2 >= 0)
return 1; /* blind growing: do not alter anything outside the session */
if (!(o->fabricated_disc_status == BURN_DISC_APPENDABLE || if (!(o->fabricated_disc_status == BURN_DISC_APPENDABLE ||
(o->fabricated_disc_status == BURN_DISC_BLANK && (o->fabricated_disc_status == BURN_DISC_BLANK &&

View File

@ -75,10 +75,10 @@ job parameters. It rather states its desires which libisoburn tries to
fulfill, or else will refuse to start the write run. fulfill, or else will refuse to start the write run.
Setup for Growing or Modifying Setup for Growing, Modifying or Blind Growing
The connector function family offers two alternative API calls for performing The connector function family offers two alternative API calls for performing
the setup for two alternative image generation strategies. the setup for several alternative image generation strategies.
Growing: Growing:
If input and output drive is the same, then isoburn_prepare_disc() is to If input and output drive is the same, then isoburn_prepare_disc() is to
@ -93,6 +93,16 @@ generation run, use isoburn_prepare_new_image(). The run will copy file data
from an eventual input drive with valid image, add any newly introduced data from an eventual input drive with valid image, add any newly introduced data
from the local filesystem, and produce a first session on output media. from the local filesystem, and produce a first session on output media.
Blind Growing:
This method reads the old image from one drive and writes the add-on session
to a different drive. That output drive is nevertheless supposed to
finally lead to the same media from where the session was loaded. Usually it
will be stdio:/dev/fd/1 (i.e. stdout) being piped into some burn program
like with this classic gesture:
mkisofs -M $dev -C $msc1,$nwa | cdrecord -waiti dev=$dev
Blind growing is prepared by the call isoburn_prepare_blind_grow().
The input drive should be released immediately after this call.
After either of these setups, some peripheral libburn drive parameter settings After either of these setups, some peripheral libburn drive parameter settings
like burn_write_opts_set_simulate(), burn_write_opts_set_multi(), like burn_write_opts_set_simulate(), burn_write_opts_set_multi(),
burn_drive_set_speed(), burn_write_opts_set_underrun_proof() should be made. burn_drive_set_speed(), burn_write_opts_set_underrun_proof() should be made.
@ -1068,7 +1078,8 @@ int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
int flag); int flag);
/** Create a disc object for writing the new session from the created or loaded /** To choose the expansion method of Growing:
Create a disc object for writing the new session from the created or loaded
iso_volset which has been manipulated via libisofs, to the same media from iso_volset which has been manipulated via libisofs, to the same media from
where the image was eventually loaded. This struct burn_disc is ready for where the image was eventually loaded. This struct burn_disc is ready for
use by a subsequent call to isoburn_disc_write(). use by a subsequent call to isoburn_disc_write().
@ -1085,9 +1096,10 @@ int isoburn_prepare_disc(struct burn_drive *drive, struct burn_disc **disc,
struct isoburn_imgen_opts *opts); struct isoburn_imgen_opts *opts);
/** Create a disc object for producing a new image from a previous image /** To choose the expansion method of Modifying:
Create a disc object for producing a new image from a previous image
plus the changes made by user. The generated burn_disc is suitable plus the changes made by user. The generated burn_disc is suitable
to be written to any grabbed libburn drive with blank writeable media. to be written to a grabbed drive with blank writeable media.
But you must not use the same drive for input and output, because data But you must not use the same drive for input and output, because data
will be read from the source drive while at the same time the target will be read from the source drive while at the same time the target
drive is already writing. drive is already writing.
@ -1095,15 +1107,11 @@ int isoburn_prepare_disc(struct burn_drive *drive, struct burn_disc **disc,
is done and the drive is BURN_DRIVE_IDLE again after asynchronous is done and the drive is BURN_DRIVE_IDLE again after asynchronous
burn_disc_write(). burn_disc_write().
@since 0.1.0 @since 0.1.0
@param in_drive The input drive,grabbed with isoburn_drive_scan_and_grab(). @param in_drive The input drive, grabbed with isoburn_drive_aquire() or
one of its alternatives.
@param disc Returns the newly created burn_disc object. @param disc Returns the newly created burn_disc object.
@param opts Options for image generation and data transport to media. @param opts Options for image generation and data transport to media.
@param out_drive The libburn drive which shall be write target. @param out_drive The output drive, from isoburn_drive_aquire() et.al..
If the drive was grabbed via libisoburn then it can later
access the libisofs source fifo via
isoburn_get_fifo_status().
Mere libburn drives cannot obtain this info.
In that case out_drive may be NULL, as well.
@return <=0 error , 1 = success @return <=0 error , 1 = success
*/ */
int isoburn_prepare_new_image(struct burn_drive *in_drive, int isoburn_prepare_new_image(struct burn_drive *in_drive,
@ -1111,7 +1119,52 @@ int isoburn_prepare_new_image(struct burn_drive *in_drive,
struct isoburn_imgen_opts *opts, struct isoburn_imgen_opts *opts,
struct burn_drive *out_drive); struct burn_drive *out_drive);
/** @since 0.1.0
/** To choose the expansion method of Blind Growing:
Create a disc object for writing an add-on session from the created or
loaded IsoImage which has been manipulated via libisofs, to a different
drive than the one from where it was loaded.
Usually output will be stdio:/dev/fd/1 (i.e. stdout) being piped
into some burn program like with this classic gesture:
mkisofs -M $dev -C $msc1,$nwa | cdrecord -waiti dev=$dev
Parameter translation into libisoburn:
$dev is the address by which parameter in_drive of this call was aquired
$msc1 was set by isoburn_set_msc1() before image reading
or was detected from the in_drive media
$nwa is a parameter of this call
or can be used as detected from the in_drive media
This call waits for libisofs output to become available and then detaches
the input drive object from the data source object by which libisofs was
reading from the input drive.
So, as far as libisofs is concerned, that drive may be released immediately
after this call in order to allow the consumer to access the drive for
writing.
The consumer should wait for input to become available and only then open
its burn drive. With cdrecord this is caused by option -waiti.
The resulting burn_disc object has to be disposed when all its writing
is done and the drive is BURN_DRIVE_IDLE again after asynchronous
burn_disc_write().
@since 0.2.2
@param in_drive The input drive,grabbed with isoburn_drive_scan_and_grab().
@param disc Returns the newly created burn_disc object.
@param opts Options for image generation and data transport to media.
@param out_drive The output drive, from isoburn_drive_aquire() et.al..
typically stdio:/dev/fd/1 .
@param nwa The address (2048 byte block count) where the add-on
session will be finally stored on a mountable media
or in a mountable file.
If nwa is -1 then the address is used as determined from
the in_drive media.
@return <=0 error , 1 = success
*/
int isoburn_prepare_blind_grow(struct burn_drive *d, struct burn_disc **disc,
struct isoburn_imgen_opts *opts,
struct burn_drive *out_drive, int nwa);
/**
Revoke isoburn_prepare_new_image() or isoburn_prepare_disc() instead of Revoke isoburn_prepare_new_image() or isoburn_prepare_disc() instead of
running isoburn_disc_write(). running isoburn_disc_write().
libisofs reserves resources and maybe already starts generating the libisofs reserves resources and maybe already starts generating the
@ -1193,8 +1246,7 @@ int isoburn_drive_wrote_well(struct burn_drive *d);
int isoburn_activate_session(struct burn_drive *drive); int isoburn_activate_session(struct burn_drive *drive);
/** @since 0.1.0 /** Wait after normal end of operations until libisofs ended all write
Wait after normal end of operations until libisofs ended all write
threads and freed resource reservations. threads and freed resource reservations.
This call is not mandatory. But without it, messages from the ending This call is not mandatory. But without it, messages from the ending
threads might appear after the application ended its write procedure. threads might appear after the application ended its write procedure.
@ -1210,21 +1262,6 @@ int isoburn_sync_after_write(struct burn_drive *input_drive,
struct burn_drive *output_drive, int flag); struct burn_drive *output_drive, int flag);
#if 0
/* >>> NOT YET IMPLEMENTED <<< */
/** Write a new session to a disc.
This is a synchronous call equivalent to isoburn_prepare_disc +
isoburn_disc_write + isoburn_activate_session
@param pacifier_func If not NULL: a function to produce appeasing messages.
See burn_abort_pacifier() in libburn.h for an example.
*/
/* TODO implement this */
int isoburn_perform_write(struct burn_write_opts *o,
int (*pacifier_func)(void *handle, int patience,
int elapsed));
#endif /* 0 */
/** Release an aquired drive. /** Release an aquired drive.
Wrapper for: burn_drive_release() Wrapper for: burn_drive_release()
@since 0.1.0 @since 0.1.0

View File

@ -1 +1 @@
#define Xorriso_timestamP "2008.07.04.070001" #define Xorriso_timestamP "2008.07.05.132528"