/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* vim: set ts=8 sts=8 sw=8 noet : */ #define _GNU_SOURCE #include "libisofs.h" #include "libburn/libburn.h" #include #include #include #include #include #include #include #include #include #include #include #include #define SECSIZE 2048 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"); } void help() { printf( "Options:\n" " -J Add Joliet support\n" " -R Add Rock Ridge support\n" " -L Set the ISO level (1 or 2)\n" " -h Print this message\n" ); } 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_tree_node_dir *root; struct burn_source *wsrc; int c; struct iso_tree_radd_dir_behavior behav = {0,0,0}; int level=1, flags=0; int ret = 0; while ((c = getopt(argc, argv, optstring)) != -1) { switch(c) { case 'h': usage(); help(); exit(0); break; case 'J': flags |= ECMA119_JOLIET; break; case 'R': flags |= ECMA119_ROCKRIDGE; break; case 'L': level = atoi(optarg); break; case '?': usage(); exit(1); break; } } if (argc < optind + 1) { printf ("Please supply device name\n"); usage(); return 1; } if (argc < optind + 2) { printf ("Please supply directory to add to disc\n"); usage(); return 1; } 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]); 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 create data source.\n"); ret = 1; goto exit_cleanup; } ropts.block = 0; /* image always start on first block */ ropts.norock = 0; ropts.nojoliet = 0; ropts.preferjoliet = 0; ropts.mode = 0555; ropts.uid = 0; ropts.gid = 0; volset = iso_volset_read(rsrc, &ropts); if (volset == NULL) { printf ("Error reading image\n"); ret = 1; goto exit_cleanup; } printf("Image size: %d blocks.\n", ropts.size); /* close source, no more needed */ data_source_free(rsrc); root = iso_volume_get_root(iso_volset_get_volume(volset, 0)); /* add a new dir */ iso_tree_radd_dir(root, argv[optind+1], &behav); memset(&wopts, 0, sizeof(struct ecma119_source_opts)); wopts.level = level; wopts.flags = flags; wopts.relaxed_constraints = 0; wopts.input_charset = "UTF-8"; wopts.ouput_charset = "UTF-8"; /* round up to 32kb aligment = 16 block*/ wopts.ms_block = ((ropts.size + 15) / 16 ) * 16; wopts.overwrite = calloc(32, 2048); wsrc = iso_source_new_ecma119(volset, &wopts); /* 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, 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, wopts.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"); 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; }