From 161bf5748c1c6b66c96701bdb8b59044953344c2 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 5 Jul 2008 13:25:06 +0000 Subject: [PATCH] New API function isoburn_prepare_blind_grow() for -as mkisofs -multi --- libisoburn/trunk/libisoburn/burn_wrap.c | 17 ++++ libisoburn/trunk/libisoburn/data_source.c | 26 ++++++ libisoburn/trunk/libisoburn/isoburn.c | 78 +++++++++++++--- libisoburn/trunk/libisoburn/isoburn.h | 41 ++++++++- libisoburn/trunk/libisoburn/isofs_wrap.c | 7 +- libisoburn/trunk/libisoburn/libisoburn.h | 97 ++++++++++++++------ libisoburn/trunk/xorriso/xorriso_timestamp.h | 2 +- 7 files changed, 224 insertions(+), 44 deletions(-) diff --git a/libisoburn/trunk/libisoburn/burn_wrap.c b/libisoburn/trunk/libisoburn/burn_wrap.c index d632bcd7..4181cab7 100644 --- a/libisoburn/trunk/libisoburn/burn_wrap.c +++ b/libisoburn/trunk/libisoburn/burn_wrap.c @@ -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) { int ret; diff --git a/libisoburn/trunk/libisoburn/data_source.c b/libisoburn/trunk/libisoburn/data_source.c index 739cc072..e465a1a1 100644 --- a/libisoburn/trunk/libisoburn/data_source.c +++ b/libisoburn/trunk/libisoburn/data_source.c @@ -85,6 +85,19 @@ int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) icd = (struct isoburn_cached_drive *) src->data; 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; aligned_lba= lba & ~(Libisoburn_tile_blockS - 1); @@ -189,6 +202,19 @@ static void ds_free_data(IsoDataSource *src) 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 *ret; diff --git a/libisoburn/trunk/libisoburn/isoburn.c b/libisoburn/trunk/libisoburn/isoburn.c index 45591226..ba50d7d0 100644 --- a/libisoburn/trunk/libisoburn/isoburn.c +++ b/libisoburn/trunk/libisoburn/isoburn.c @@ -119,6 +119,7 @@ int isoburn_new(struct isoburn **objpt, int flag) o->drive= NULL; o->emulation_mode= 0; o->fabricated_msc1= -1; + o->fabricated_msc2= -1; o->zero_nwa= Libisoburn_overwriteable_starT; o->min_start_byte= o->zero_nwa * 2048; o->nwa= o->zero_nwa; @@ -130,6 +131,7 @@ int isoburn_new(struct isoburn **objpt, int flag) for(i=0;itarget_iso_head[i]= 0; o->image= NULL; + o->iso_data_source= NULL; o->read_pacifier= NULL; o->read_pacifier_handle= 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 */ if(o->iso_source!=NULL) burn_source_free(o->iso_source); - + if(o->iso_data_source!=NULL) + iso_data_source_unref(o->iso_data_source); free((char *) o); *objpt= NULL; 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 int isoburn_prepare_disc_aux(struct burn_drive *in_d, struct burn_drive *out_d, 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_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; IsoWriteOpts *wopts= NULL; 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); 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_fifo_size(wopts, fifo_chunks); - - ret = isoburn_disc_track_lba_nwa(out_d, NULL, 0, &lba, &nwa); + ret= isoburn_get_msc2(out_o, NULL, &nwa, 0); if (ret != 1) { isoburn_msgs_submit(out_o, 0x00060000, "Cannot determine next writeable address", 0, "FAILURE", 0); {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); opts->effective_lba= nwa; 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); {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 */ @@ -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 @param flag bit0= this is a regular end, not an abort give up source reference diff --git a/libisoburn/trunk/libisoburn/isoburn.h b/libisoburn/trunk/libisoburn/isoburn.h index a26df513..21c18f76 100644 --- a/libisoburn/trunk/libisoburn/isoburn.h +++ b/libisoburn/trunk/libisoburn/isoburn.h @@ -60,9 +60,17 @@ struct isoburn { */ 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 media (usually Libisoburn_overwriteable_starT, but might be forced to 0) - */ + */ int zero_nwa; /* Start address as given by image examination (bytes, not blocks) */ @@ -71,6 +79,7 @@ struct isoburn { /* Aligned start address to be used for processing (counted in blocks) */ int nwa; + /* Truncate to .nwa an eventual regular file serving as output drive */ int truncate; @@ -99,6 +108,10 @@ struct isoburn { /* Libisofs image context */ 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. 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); +/** 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() function. @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 * 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. diff --git a/libisoburn/trunk/libisoburn/isofs_wrap.c b/libisoburn/trunk/libisoburn/isofs_wrap.c index ec1068d3..c5443212 100644 --- a/libisoburn/trunk/libisoburn/isofs_wrap.c +++ b/libisoburn/trunk/libisoburn/isofs_wrap.c @@ -212,6 +212,9 @@ create_blank_image:; */ 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, isoburn_idle_free_function); if(o->read_pacifier_handle==NULL) @@ -221,7 +224,7 @@ create_blank_image:; ret = iso_image_import(o->image, ds, ropts, &features); iso_tree_set_report_callback(o->image, NULL); iso_read_opts_free(ropts); - iso_data_source_unref(ds); + if (ret < 0) { isoburn_report_iso_error(ret, "Cannot import image", 0, "FAILURE", 0); return ret; @@ -277,6 +280,8 @@ int isoburn_activate_session(struct burn_drive *drive) if (o->emulation_mode != 1) 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 || (o->fabricated_disc_status == BURN_DISC_BLANK && diff --git a/libisoburn/trunk/libisoburn/libisoburn.h b/libisoburn/trunk/libisoburn/libisoburn.h index 71607e1d..f93eff7c 100644 --- a/libisoburn/trunk/libisoburn/libisoburn.h +++ b/libisoburn/trunk/libisoburn/libisoburn.h @@ -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. - Setup for Growing or Modifying + Setup for Growing, Modifying or Blind Growing 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: 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 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 like burn_write_opts_set_simulate(), burn_write_opts_set_multi(), 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); -/** 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 where the image was eventually loaded. This struct burn_disc is ready for 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); -/** 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 - 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 will be read from the source drive while at the same time the target 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 burn_disc_write(). @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 opts Options for image generation and data transport to media. - @param out_drive The libburn drive which shall be write target. - 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. + @param out_drive The output drive, from isoburn_drive_aquire() et.al.. @return <=0 error , 1 = success */ 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 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 running isoburn_disc_write(). 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); -/** @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. This call is not mandatory. But without it, messages from the ending 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); -#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. Wrapper for: burn_drive_release() @since 0.1.0 diff --git a/libisoburn/trunk/xorriso/xorriso_timestamp.h b/libisoburn/trunk/xorriso/xorriso_timestamp.h index 51bab3bf..afe32316 100644 --- a/libisoburn/trunk/xorriso/xorriso_timestamp.h +++ b/libisoburn/trunk/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.07.04.070001" +#define Xorriso_timestamP "2008.07.05.132528"