From 0746d622e443ed6ce30b2435fccc79fd1e5c3255 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 30 Aug 2007 21:55:36 +0000 Subject: [PATCH] Provide better support for overwriteable media --- Makefile.am | 4 +- libisofs/ecma119.c | 12 +-- libisofs/libisofs.h | 24 ++---- test/iso_grow.c | 190 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 174 insertions(+), 56 deletions(-) diff --git a/Makefile.am b/Makefile.am index d3fab19..cfe11ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,8 +73,8 @@ test_isoadd_CPPFLAGS = -Ilibisofs test_isoadd_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) test_isoadd_SOURCES = test/iso_add.c -test_isogrow_CPPFLAGS = -Ilibisofs -test_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) +test_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn +test_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn test_isogrow_SOURCES = test/iso_grow.c ## Build unit test diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 6ee3886..0af05fd 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -430,17 +430,19 @@ ecma119_target_new(struct iso_volset *volset, t->total_size = (t->curblock - t->ms_block) * t->block_size; - if (opts->dvd_plus_rw) { + if (opts->overwrite) { /* * Get a copy of the volume descriptors to be written in a DVD+RW * disc */ uint8_t *buf; - opts->vol_desc_count = 2 + (t->eltorito ? 1 : 0) + - (t->joliet ? 1 : 0); - opts->vol_desc = calloc(opts->vol_desc_count, t->block_size); - buf = opts->vol_desc; + + /* set the 32 block buffer to 0 */ + memset(opts->overwrite, 0, 32 * t->block_size); + + /* skip the first 16 blocks (system area) */ + buf = opts->overwrite + 16 * t->block_size; /* * In the PVM to be written in the 16th sector of the disc, we diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index b419325..84cc67b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -277,26 +277,12 @@ struct ecma119_source_opts { * image, used to read file contents. * Otherwise it can be NULL. */ - unsigned int dvd_plus_rw:1; + uint8_t *overwrite; /**< - * When 1, vol_desc and vol_desc_count will be filled propertly - * with information useful for "growing" a DVD+RW. - */ - uint8_t *vol_desc; - /**< - * If dvd_plus_rw is set to one, this will be filled with a - * pointer to a memory region containing a copy of the - * volume descriptors of the image, including the volume - * descriptor set terminator. - * A suitable program can write the contents of this memory - * region from sector 16 of a DVD+RW to "grow" its image. - * The size of this region will be vol_desc_count * 2048 and - * should be freed by user when no more needed. - */ - int vol_desc_count; - /**< - * If dvd_plus_rw is set to one, this will be filled with the - * number of volume descriptors written to vol_desc. + * When not NULL, it should point to a buffer of at least + * 64KiB, where libisofs will write the contents that should + * be written at the beginning of a overwriteable media, to + * grow the image. */ }; diff --git a/test/iso_grow.c b/test/iso_grow.c index 46f11b7..b90f26d 100644 --- a/test/iso_grow.c +++ b/test/iso_grow.c @@ -24,6 +24,8 @@ const char * const optstring = "JRL:h"; extern char *optarg; extern int optind; +static struct data_source *libburn_data_source_new(struct burn_drive *d); + void usage() { printf("test [OPTIONS] DISC DIRECTORY\n"); @@ -42,20 +44,18 @@ void help() int main(int argc, char **argv) { + struct burn_drive_info *drives; + struct burn_drive *drive; struct ecma119_source_opts wopts; struct ecma119_read_opts ropts; struct data_source *rsrc; struct iso_volset *volset; - struct iso_volume *volume; struct iso_tree_node_dir *root; struct burn_source *wsrc; - unsigned char buf[2048]; - int fd; int c; - int constraints; struct iso_tree_radd_dir_behavior behav = {0,0,0}; int level=1, flags=0; - char *boot_img = NULL; + int ret = 0; while ((c = getopt(argc, argv, optstring)) != -1) { switch(c) { @@ -94,13 +94,44 @@ int main(int argc, char **argv) if (!iso_init()) { err(1, "Can't init libisofs"); } + if (!burn_initialize()) { + err(1, "Can't init libburn"); + } iso_msgs_set_severities("NEVER", "ALL", ""); + burn_msgs_set_severities("NEVER", "SORRY", "libburner : "); printf("Reading from %s\n", argv[optind]); - rsrc = data_source_from_file(argv[optind]); + + if (burn_drive_scan_and_grab(&drives, argv[optind], 0) != 1) { + err(1, "Can't open device. Are you sure it is a valid drive?\n"); + } + + drive = drives[0].drive; + + { + /* some check before going on */ + enum burn_disc_status state; + int pno; + char name[80]; + + state = burn_disc_get_status(drive); + burn_disc_get_profile(drive, &pno, name); + + // my drives report BURN_DISC_BLANK on a DVD+RW with data. + // is that correct? + if ( (pno != 0x1a) /*|| (state != BURN_DISC_FULL)*/ ) { + printf("You need to insert a DVD+RW with some data.\n"); + printf("Profile: %x, state: %d.\n", pno, state); + ret = 1; + goto exit_cleanup; + } + } + + rsrc = libburn_data_source_new(drive); if (rsrc == NULL) { - printf ("Can't open device\n"); - return 1; + printf ("Can't create data source.\n"); + ret = 1; + goto exit_cleanup; } ropts.block = 0; /* image always start on first block */ @@ -114,7 +145,8 @@ int main(int argc, char **argv) if (volset == NULL) { printf ("Error reading image\n"); - return 1; + ret = 1; + goto exit_cleanup; } printf("Image size: %d blocks.\n", ropts.size); @@ -134,38 +166,136 @@ int main(int argc, char **argv) wopts.input_charset = "UTF-8"; wopts.ouput_charset = "UTF-8"; wopts.ms_block = ropts.size; - wopts.dvd_plus_rw = 1; + wopts.overwrite = malloc(32*2048); wsrc = iso_source_new_ecma119(volset, &wopts); - fd = open(argv[optind], O_WRONLY); - if ( fd == -1 ) { - printf ("Can't write to disc\n"); - return 1; - } - printf("HERE %d\n", wopts.vol_desc_count); /* a. write the new image */ printf("Adding new data...\n"); - if ( lseek(fd, ropts.size * 2048, SEEK_SET) == (off_t) -1) { - printf ("Can't seek to new location\n"); - return 1; - } - - while (wsrc->read(wsrc, buf, 2048) == 2048) { - write(fd, buf, 2048); + { + struct burn_disc *target_disc; + struct burn_session *session; + struct burn_write_opts *burn_options; + struct burn_track *track; + struct burn_progress progress; + char reasons[BURN_REASONS_LEN]; + + target_disc = burn_disc_create(); + session = burn_session_create(); + burn_disc_add_session(target_disc, session, BURN_POS_END); + + track = burn_track_create(); + burn_track_set_source(track, wsrc); + burn_session_add_track(session, track, BURN_POS_END); + + burn_options = burn_write_opts_new(drive); + burn_drive_set_speed(drive, 0, 0); + burn_write_opts_set_underrun_proof(burn_options, 1); + + //mmm, check for 32K alignment? + burn_write_opts_set_start_byte(burn_options, ropts.size * 2048); + + if (burn_write_opts_auto_write_type(burn_options, target_disc, + reasons, 0) == BURN_WRITE_NONE) { + printf("Failed to find a suitable write mode:\n%s\n", reasons); + ret = 1; + goto exit_cleanup; + } + + /* ok, write the new track */ + burn_disc_write(burn_options, target_disc); + burn_write_opts_free(burn_options); + + while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING) + usleep(1002); + + while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) { + printf("Writing: sector %d of %d\n", progress.sector, progress.sectors); + sleep(1); + } + } /* b. write the new vol desc */ printf("Writing the new vol desc...\n"); - if ( lseek(fd, 16 * 2048, SEEK_SET) == (off_t) -1) { - printf ("Can't seek to 16th sector\n"); - return 1; - } - write(fd, wopts.vol_desc, 2048 * wopts.vol_desc_count); - fsync(fd); - close(fd); + if ( burn_random_access_write(drive, 0, wopts.overwrite, 32*2048, 0) != 1) { + printf("Ups, new vol desc write failed\n"); + } + + free(wopts.overwrite); + iso_volset_free(volset); +exit_cleanup:; + burn_drive_release(drives[0].drive, 0); + burn_finish(); iso_finish(); + + exit(ret); +} +struct disc_data_src { + struct burn_drive *d; + int nblocks; +}; + +static int +libburn_ds_read_block(struct data_source *src, int lba, unsigned char *buffer) +{ + struct disc_data_src *data; + off_t data_count; + + assert(src && buffer); + + data = (struct disc_data_src*)src->data; + + /* if (lba >= data->nblocks) + * return BLOCK_OUT_OF_FILE; + */ + + if ( burn_read_data(data->d, (off_t) lba * (off_t) 2048, buffer, 2048, + &data_count, 0) < 0 ) { + return -1; //error + } + return 0; } + +static int +libburn_ds_get_size(struct data_source *src) +{ + struct disc_data_src *data; + + assert(src); + + data = (struct disc_data_src*)src->data; + return data->nblocks; +} + +static void +libburn_ds_free_data(struct data_source *src) +{ + free(src->data); +} + +static struct data_source * +libburn_data_source_new(struct burn_drive *d) +{ + struct disc_data_src *data; + struct data_source *ret; + + assert(d); + + data = malloc(sizeof(struct disc_data_src)); + data->d = d; + + //should be filled with the size of disc (or track?) + data->nblocks = 0; + + ret = malloc(sizeof(struct data_source)); + ret->refcount = 1; + ret->read_block = libburn_ds_read_block; + ret->get_size = libburn_ds_get_size; + ret->free_data = libburn_ds_free_data; + ret->data = data; + return ret; +}