diff --git a/.bzrignore b/.bzrignore index c875645..79c4be0 100644 --- a/.bzrignore +++ b/.bzrignore @@ -34,3 +34,4 @@ demo/isoread demo/isocat demo/isomodify demo/isoms +demo/isogrow diff --git a/Makefile.am b/Makefile.am index 65d5cd3..d9f13da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,7 +61,8 @@ noinst_PROGRAMS = \ demo/isoread \ demo/isocat \ demo/isomodify \ - demo/isoms + demo/isoms \ + demo/isogrow demo_lsl_CPPFLAGS = -Isrc demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) @@ -103,6 +104,10 @@ demo_isoms_CPPFLAGS = -Isrc demo_isoms_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_isoms_SOURCES = demo/iso_ms.c +demo_isogrow_CPPFLAGS = -Isrc -Ilibburn +demo_isogrow_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn +demo_isogrow_SOURCES = demo/iso_grow.c + ## Build unit test diff --git a/demo/iso_grow.c b/demo/iso_grow.c new file mode 100644 index 0000000..a89dec9 --- /dev/null +++ b/demo/iso_grow.c @@ -0,0 +1,259 @@ +/* + * Very simple program to show how to grow an iso image. + */ + +#include "libisofs.h" +#include "libburn/libburn.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static IsoDataSource *libburn_data_source_new(struct burn_drive *d); + +void usage(char **argv) +{ + printf("%s DISC DIRECTORY\n", argv[0]); +} + +int main(int argc, char **argv) +{ + int result; + IsoImage *image; + IsoDataSource *src; + struct burn_source *burn_src; + struct burn_drive_info *drives; + struct burn_drive *drive; + unsigned char buf[32 * 2048]; + int ret = 0; + struct iso_read_image_features features; + Ecma119WriteOpts opts = { + 1, /* level */ + 1, /* rockridge */ + 0, /* omit_version_numbers */ + 0, /* allow_deep_paths */ + 1, /* sort files */ + 0, /* replace_dir_mode */ + 0, /* replace_file_mode */ + 0, /* replace_uid */ + 0, /* replace_gid */ + 0, /* dir_mode */ + 0, /* file_mode */ + 0, /* uid */ + 0, /* gid */ + NULL, /* output charset */ + 0, /* appendable */ + 0, /* ms_block */ + NULL /* overwrite */ + }; + struct iso_read_opts ropts = { + 0, /* block */ + 0, /* norock */ + 0, /* nojoliet */ + 0, /* preferjoliet */ + 0, /* uid; */ + 0, /* gid; */ + 0, /* mode */ + "UTF-8" /* input_charset */ + }; + + if (argc < 3) { + usage(argv); + return 1; + } + + /* create the image context */ + result = iso_image_new("volume_id", &image); + if (result < 0) { + printf ("Error creating image\n"); + return 1; + } + iso_image_set_msgs_severities(image, "NEVER", "ALL", ""); + iso_tree_set_follow_symlinks(image, 0); + iso_tree_set_ignore_hidden(image, 0); + iso_tree_set_stop_on_error(image, 0); + + if (!burn_initialize()) { + err(1, "Can't init libburn"); + } + burn_msgs_set_severities("NEVER", "SORRY", "libburner : "); + + if (burn_drive_scan_and_grab(&drives, argv[1], 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; + } + } + + /* create the data source to accesss previous image */ + src = libburn_data_source_new(drive); + if (src == NULL) { + printf("Can't create data source.\n"); + ret = 1; + goto exit_cleanup; + } + + /* import previous image */ + ropts.block = 0; /* image always start on first block */ + result = iso_image_import(image, src, &ropts, &features); + iso_data_source_unref(src); + if (result < 0) { + printf ("Error importing previous session %d\n", result); + return 1; + } + + /* add new dir */ + result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]); + if (result < 0) { + printf ("Error adding directory %d\n", result); + return 1; + } + + /* generate a multisession image with new contents */ + /* round up to 32kb aligment = 16 block*/ + opts.ms_block = ((features.size + 15) / 16 ) * 16; + opts.appendable = 1; + opts.overwrite = buf; + result = iso_image_create_burn_source(image, &opts, &burn_src); + if (result < 0) { + printf ("Cant create image, error %d\n", result); + return 1; + } + + /* a. write the new image */ + printf("Adding new data...\n"); + { + 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, burn_src); + 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, opts.ms_block * 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"); + ret = burn_random_access_write(drive, 0, (char*)opts.overwrite, 32*2048, 0); + if (ret != 1) { + printf("Ups, new vol desc write failed\n"); + } + + iso_image_unref(image); + +exit_cleanup:; + burn_drive_release(drives[0].drive, 0); + burn_finish(); + + exit(ret); +} + +static int +libburn_ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) +{ + struct burn_drive *d; + off_t data_count; + + d = (struct burn_drive*)src->data; + + if ( burn_read_data(d, (off_t) lba * (off_t) 2048, (char*)buffer, + 2048, &data_count, 0) < 0 ) { + return -1; //error + } + + return 1; +} + +static +int libburn_ds_open(IsoDataSource *src) +{ + /* nothing to do, device is always opened */ + return 1; +} + +static +int libburn_ds_close(IsoDataSource *src) +{ + /* nothing to do, device is always opened */ + return 1; +} + +static void +libburn_ds_free_data(IsoDataSource *src) +{ + /* nothing to do */ +} + +static IsoDataSource * +libburn_data_source_new(struct burn_drive *d) +{ + IsoDataSource *ret; + + ret = malloc(sizeof(IsoDataSource)); + ret->refcount = 1; + ret->read_block = libburn_ds_read_block; + ret->open = libburn_ds_open; + ret->close = libburn_ds_close; + ret->free_data = libburn_ds_free_data; + ret->data = d; + return ret; +} diff --git a/src/ecma119.c b/src/ecma119.c index 0a2f0cc..fcdfd93 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -717,7 +717,7 @@ void *write_function(void *arg) static int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) { - int ret, i; + int ret, i, voldesc_size; Ecma119Image *target; /* 1. Allocate target and copy opts there */ @@ -801,6 +801,8 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) goto target_cleanup; } + voldesc_size = target->curblock - target->ms_block - 16; + /* Volume Descriptor Set Terminator */ target->curblock++; @@ -824,6 +826,61 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) } } + /* create the ring buffer */ + ret = iso_ring_buffer_new(&target->buffer); + if (ret < 0) { + goto target_cleanup; + } + + /* check if we need to provide a copy of volume descriptors */ + if (opts->overwrite) { + + /* + * Get a copy of the volume descriptors to be written in a DVD+RW + * disc + */ + + uint8_t *buf; + struct ecma119_vol_desc_terminator *vol; + IsoImageWriter *writer; + + /* + * In the PVM to be written in the 16th sector of the disc, we + * need to specify the full size. + */ + target->vol_space_size = target->curblock; + + /* write volume descriptor */ + for (i = 0; i < target->nwriters; ++i) { + writer = target->writers[i]; + ret = writer->write_vol_desc(writer); + if (ret < 0) { + iso_msg_debug(target->image->messenger, + "Error writing overwrite volume descriptors"); + goto target_cleanup; + } + } + + /* skip the first 16 blocks (system area) */ + buf = opts->overwrite + 16 * BLOCK_SIZE; + voldesc_size *= BLOCK_SIZE; + + /* copy the volume descriptors to the overwrite buffer... */ + ret = iso_ring_buffer_read(target->buffer, buf, voldesc_size); + if (ret < 0) { + iso_msg_debug(target->image->messenger, + "Error reading overwrite volume descriptors"); + goto target_cleanup; + } + + /* ...including the vol desc terminator */ + memset(buf + voldesc_size, 0, BLOCK_SIZE); + vol = (struct ecma119_vol_desc_terminator*) (buf + voldesc_size); + vol->vol_desc_type[0] = 255; + memcpy(vol->std_identifier, "CD001", 5); + vol->vol_desc_version[0] = 1; + } + /* * The volume space size is just the size of the last session, in * case of ms images. @@ -833,12 +890,6 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) /* 4. Create and start writting thread */ - /* create the ring buffer */ - ret = iso_ring_buffer_new(&target->buffer); - if (ret < 0) { - goto target_cleanup; - } - /* ensure the thread is created joinable */ pthread_attr_init(&(target->th_attr)); pthread_attr_setdetachstate(&(target->th_attr), PTHREAD_CREATE_JOINABLE); @@ -969,7 +1020,8 @@ int iso_write(Ecma119Image *target, void *buf, size_t count) return ISO_WRITE_ERROR; } - if (ret > 0){ + /* total size is 0 when writing the overwrite buffer */ + if (ret > 0 && (target->total_size != (off_t) 0)){ unsigned int kbw, kbt; int percent;