From 31650eb98878940195c15a5a0cff83158bc21822 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 4 Sep 2007 22:50:04 +0000 Subject: [PATCH] New API calls burn_drive_grab_dummy(), burn_drive_get_drive_role() --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/async.c | 42 +++++-- libburn/drive.c | 230 +++++++++++++++++++++++++++++----- libburn/libburn.h | 36 +++++- libburn/libdax_msgs.h | 5 + libburn/options.c | 2 + libburn/read.c | 94 ++++++++++++-- libburn/spc.c | 10 +- libburn/transport.h | 3 + libburn/write.c | 240 ++++++++++++++++++++++++++++++++++-- 10 files changed, 591 insertions(+), 73 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 25be398..2cd2f1c 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2007.09.01.182319" +#define Cdrskin_timestamP "2007.09.04.224905" diff --git a/libburn/async.c b/libburn/async.c index 3ae2358..e6c5c04 100644 --- a/libburn/async.c +++ b/libburn/async.c @@ -96,7 +96,7 @@ static void add_worker(struct burn_drive *d, WorkerFunc f, void *data) tmp = workers; workers = a; - if (d) + if (d != NULL) d->busy = BURN_DRIVE_SPAWNING; if (pthread_create(&a->thread, NULL, f, a)) { @@ -211,9 +211,6 @@ void burn_disc_erase(struct burn_drive *drive, int fast) { struct erase_opts o; - /* A70103 : will be set to 0 by burn_disc_erase_sync() */ - drive->cancel = 1; - /* ts A61006 */ /* a ssert(drive); */ /* a ssert(!SCAN_GOING()); */ @@ -233,6 +230,8 @@ void burn_disc_erase(struct burn_drive *drive, int fast) 0, 0); return; } + /* A70103 : will be set to 0 by burn_disc_erase_sync() */ + drive->cancel = 1; /* ts A70103 moved up from burn_disc_erase_sync() */ /* ts A60825 : allow on parole to blank appendable CDs */ @@ -247,6 +246,8 @@ void burn_disc_erase(struct burn_drive *drive, int fast) (drive->status != BURN_DISC_FULL && drive->status != BURN_DISC_APPENDABLE && drive->status != BURN_DISC_BLANK) + || + (drive->drive_role != 1) ) { libdax_msgs_submit(libdax_messenger, drive->global_index, 0x00020130, @@ -287,6 +288,14 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag) 0, 0); return; } + if (drive->drive_role != 1) { + libdax_msgs_submit(libdax_messenger, drive->global_index, + 0x00020146, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Drive is a virtual placeholder", 0, 0); + drive->cancel = 1; + return; + } if (flag & 128) /* application prescribed format type */ flag |= 16; /* enforce re-format */ @@ -339,13 +348,6 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) #endif - /* For the next lines any return indicates failure */ - opts->drive->cancel = 1; - - /* ts A70203 : people have been warned in API specs */ - if (opts->write_type == BURN_WRITE_NONE) - return; - /* ts A61006 */ /* a ssert(!SCAN_GOING()); */ /* a ssert(!find_worker(opts->drive)); */ @@ -357,8 +359,24 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) 0, 0); return; } + + /* For the next lines any return indicates failure */ + opts->drive->cancel = 1; + + /* ts A70203 : people have been warned in API specs */ + if (opts->write_type == BURN_WRITE_NONE) + return; + + if (opts->drive->drive_role == 0) { + libdax_msgs_submit(libdax_messenger, opts->drive->global_index, + 0x00020146, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Drive is a virtual placeholder (null-drive)", 0, 0); + return; + } + /* ts A61007 : obsolete Assert in spc_select_write_params() */ - if (!opts->drive->mdata->valid) { + if (opts->drive->drive_role == 1 && !opts->drive->mdata->valid) { libdax_msgs_submit(libdax_messenger, opts->drive->global_index, 0x00020113, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, diff --git a/libburn/drive.c b/libburn/drive.c index 56f078c..992d946 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -35,6 +35,9 @@ /* A70225 : to learn about eventual Libburn_dvd_r_dl_multi_no_close_sessioN */ #include "write.h" +/* A70903 : for burn_scsi_setup_drive() */ +#include "spc.h" + #include "libdax_msgs.h" extern struct libdax_msgs *libdax_messenger; @@ -47,11 +50,30 @@ int burn_setup_drive(struct burn_drive *d, char *fname) { d->devname = burn_strdup(fname); memset(&d->params, 0, sizeof(struct params)); + d->idata = NULL; + d->mdata = NULL; + d->toc_entry = NULL; d->released = 1; d->status = BURN_DISC_UNREADY; return 1; } + +/* ts A70903 */ +void burn_drive_free_subs(struct burn_drive *d) +{ + if (d->idata != NULL) + free((void *) d->idata); + if (d->mdata != NULL) { + burn_mdata_free_subs(d->mdata); + free((void *) d->mdata); + } + if(d->toc_entry != NULL) + free((void *) d->toc_entry); + free(d->devname); +} + + /* ts A60904 : ticket 62, contribution by elmom */ /* splitting former burn_drive_free() (which freed all, into two calls) */ void burn_drive_free(struct burn_drive *d) @@ -59,14 +81,10 @@ void burn_drive_free(struct burn_drive *d) if (d->global_index == -1) return; /* ts A60822 : close open fds before forgetting them */ - if (burn_drive_is_open(d)) - d->release(d); - free((void *) d->idata); - burn_mdata_free_subs(d->mdata); - free((void *) d->mdata); - if(d->toc_entry != NULL) - free((void *) d->toc_entry); - free(d->devname); + if (d->drive_role == 1) + if (burn_drive_is_open(d)) + d->release(d); + burn_drive_free_subs(d); d->global_index = -1; } @@ -327,6 +345,8 @@ struct burn_drive *burn_drive_finish_enum(struct burn_drive *d) <<< debug: for tracing calls which might use open drive fds */ int mmc_function_spy(char * text); + d->drive_role = 1; /* MMC drive */ + t = burn_drive_register(d); /* ts A60821 */ @@ -399,10 +419,13 @@ void burn_drive_release(struct burn_drive *d, int le) return; } - d->unlock(d); - if (le) - d->eject(d); - d->release(d); + if (d->drive_role == 1) { + d->unlock(d); + if (le) + d->eject(d); + d->release(d); + } + d->released = 1; /* ts A61125 : outsourced model aspects */ @@ -485,7 +508,8 @@ void burn_disc_erase_sync(struct burn_drive *d, int fast) /* ts A61125 : update media state records */ burn_drive_mark_unready(d); - burn_drive_inquire_media(d); + if (d->drive_role == 1) + burn_drive_inquire_media(d); d->busy = BURN_DRIVE_IDLE; } @@ -513,6 +537,7 @@ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag) stages = 1 + ((flag & 1) && size > 1024 * 1024); d->cancel = 0; d->busy = BURN_DRIVE_FORMATTING; + ret = d->format_unit(d, size, flag & 0xff96); /* forward bits */ if (ret <= 0) d->cancel = 1; @@ -593,6 +618,8 @@ int burn_disc_get_formats(struct burn_drive *d, int *status, off_t *size, *size = 0; *bl_sas = 0; *num_formats = 0; + if (d->drive_role != 1) + return 0; ret = d->read_format_capacities(d, 0x00); if (ret <= 0) return 0; @@ -643,7 +670,7 @@ int burn_disc_erasable(struct burn_drive *d) enum burn_drive_status burn_drive_get_status(struct burn_drive *d, struct burn_progress *p) { - if (p) { + if (p != NULL) { memcpy(p, &(d->progress), sizeof(struct burn_progress)); /* TODO: add mutex */ } @@ -797,22 +824,6 @@ int burn_drive_scan_sync(struct burn_drive_info *drives[], return 0; } - -void burn_drive_info_free(struct burn_drive_info drive_infos[]) -{ -/* ts A60904 : ticket 62, contribution by elmom */ -/* clarifying the meaning and the identity of the victim */ - - /* ts A60904 : This looks a bit weird. - burn_drive_info is not the manager of burn_drive but only its - spokesperson. To my knowlege drive_infos from burn_drive_scan() - are not memorized globally. */ - if(drive_infos != NULL) - free((void *) drive_infos); - - burn_drive_free_all(); -} - /* ts A61001 : internal call */ int burn_drive_forget(struct burn_drive *d, int force) { @@ -846,6 +857,32 @@ int burn_drive_info_forget(struct burn_drive_info *info, int force) return burn_drive_forget(info->drive, force); } + +void burn_drive_info_free(struct burn_drive_info drive_infos[]) +{ +/* ts A60904 : ticket 62, contribution by elmom */ +/* clarifying the meaning and the identity of the victim */ + + /* ts A60904 : This looks a bit weird. + burn_drive_info is not the manager of burn_drive but only its + spokesperson. To my knowlege drive_infos from burn_drive_scan() + are not memorized globally. */ + if(drive_infos != NULL) + free((void *) drive_infos); + + /* >>> ts A70903 : THIS IS WRONG ! + It contradicts the API and endangers multi drive usage. + This call is not entitled to delete all drives, only the + ones of the array. + + Problem: it is unclear how many items are listed in drive_infos + Solution: add a dummy element to any burn_drive_info array with + drive == NULL + */ + burn_drive_free_all(); +} + + struct burn_disc *burn_drive_get_disc(struct burn_drive *d) { /* ts A61022: SIGSEGV on calling this function with blank media */ @@ -858,6 +895,9 @@ struct burn_disc *burn_drive_get_disc(struct burn_drive *d) void burn_drive_set_speed(struct burn_drive *d, int r, int w) { + d->nominal_write_speed = w; + if(d->drive_role != 1) + return; d->set_speed(d, r, w); } @@ -904,17 +944,23 @@ void burn_sectors_to_msf(int sectors, int *m, int *s, int *f) int burn_drive_get_read_speed(struct burn_drive *d) { + if(!d->mdata->valid) + return 0; return d->mdata->max_read_speed; } int burn_drive_get_write_speed(struct burn_drive *d) { + if(!d->mdata->valid) + return 0; return d->mdata->max_write_speed; } /* ts A61021 : New API function */ int burn_drive_get_min_write_speed(struct burn_drive *d) { + if(!d->mdata->valid) + return 0; return d->mdata->min_write_speed; } @@ -1383,6 +1429,8 @@ int burn_drive_get_start_end_lba(struct burn_drive *d, /* ts A61020 API function */ int burn_disc_pretend_blank(struct burn_drive *d) { + if (d->drive_role == 0) + return 0; if (d->status != BURN_DISC_UNREADY && d->status != BURN_DISC_UNSUITABLE) return 0; @@ -1393,6 +1441,8 @@ int burn_disc_pretend_blank(struct burn_drive *d) /* ts A61106 API function */ int burn_disc_pretend_full(struct burn_drive *d) { + if (d->drive_role == 0) + return 0; if (d->status != BURN_DISC_UNREADY && d->status != BURN_DISC_UNSUITABLE) return 0; @@ -1411,6 +1461,8 @@ int burn_disc_read_atip(struct burn_drive *d) 0, 0); return -1; } + if(d->drive_role != 1) + return 0; if (d->current_profile == -1 || d->current_is_cd_profile) { d->read_atip(d); /* >>> some control of success would be nice :) */ @@ -1443,6 +1495,9 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o, 0, 0); return -1; } + *lba = *nwa = 0; + if (d->drive_role != 1) + return 0; if (o != NULL) d->send_write_parameters(d, o); ret = d->get_nwa(d, trackno, lba, nwa); @@ -1471,6 +1526,9 @@ int burn_disc_get_msc1(struct burn_drive *d, int *start) 0, 0); return -1; } + *start = 0; + if (d->drive_role != 1) + return 0; ret = d->read_multi_session_c1(d, &trackno, start); return ret; } @@ -1483,13 +1541,20 @@ off_t burn_disc_available_space(struct burn_drive *d, int lba, nwa; if (burn_drive_is_released(d)) - goto ex; + return 0; if (d->busy != BURN_DRIVE_IDLE) - goto ex; + return 0; + if (d->drive_role == 0) + return 0; + if (d->drive_role == 2) { + + /* >>> how to estimate available space for a stdio file ? */ + return ((off_t) (1024 * 1024 * 1024) * (off_t) 2048); + + } if (o != NULL) d->send_write_parameters(d, o); d->get_nwa(d, -1, &lba, &nwa); -ex:; if (o != NULL) { if (o->start_byte > 0) { if (o->start_byte > d->media_capacity_remaining) @@ -1594,6 +1659,8 @@ int burn_speed_descriptor_copy(struct burn_speed_descriptor *from, /* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */ int burn_mdata_free_subs(struct scsi_mode_data *m) { + if(!m->valid) + return 0; burn_speed_descriptor_destroy(&(m->speed_descriptors), 1); return 1; } @@ -1607,6 +1674,8 @@ int burn_drive_get_speedlist(struct burn_drive *d, struct burn_speed_descriptor *sd, *csd = NULL; (*speed_list) = NULL; + if(!d->mdata->valid) + return 0; for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) { ret = burn_speed_descriptor_new(&csd, NULL, csd, 0); if (ret <= 0) @@ -1630,6 +1699,8 @@ int burn_drive_get_best_speed(struct burn_drive *d, int speed_goal, if (speed_goal < 0) best_speed = 2000000000; *best_descr = NULL; + if(!d->mdata->valid) + return 0; for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) { if (flag & 1) speed = sd->read_speed; @@ -1703,7 +1774,21 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt, o->current_is_cd_profile = d->current_is_cd_profile; o->might_simulate = 0; - if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) { + if (d->drive_role == 0) + return 0; + if (d->drive_role == 2) { + /* stdio file dummy drive */ + o->start_adr = 1; + + size = ((off_t) (1024 * 1024 * 1024) * (off_t) 2048); + /* >>> obtain realistic file size */ + o->start_range_high = size; + + o->start_alignment = 2048; /* imposting a drive, not a file */ + o->might_do_sao = 4; + o->might_do_tao = 2; + o->advised_write_mode = BURN_WRITE_TAO; + } else if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) { return 0; } else if (s == BURN_DISC_APPENDABLE && (wt == BURN_WRITE_SAO || wt == BURN_WRITE_RAW)) { @@ -1880,3 +1965,80 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc, } return (disc->sessions > 0); } + + +/* ts A70903 : API */ +int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) +{ + int ret; + struct burn_drive *d= NULL, *regd_d; + struct stat stbuf; + + if (fname[0] != 0) { + if (stat(fname, &stbuf) == -1) { + + /* >>> ? reject ? try to create ? */; + + } else if(S_ISREG(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) { + /* >>> ? open for a test ? */; + } else { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020149, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Unsuitable filetype for pseudo-drive", 0, 0); + return 0; + } + } + d= (struct burn_drive *) calloc(1, sizeof(struct burn_drive)); + if (d == NULL) + return 0; + d->status = BURN_DISC_EMPTY; + burn_setup_drive(d, fname); + + if (fname[0] != 0) + d->drive_role = 2; + else + d->drive_role = 0; + ret = burn_scsi_setup_drive(d, -1, -1, -1, -1, -1, 0); + if (ret <= 0) + goto ex; + regd_d = burn_drive_register(d); + if (regd_d == NULL) { + ret = -1; + goto ex; + } + if (d->drive_role == 2) { + d->status = BURN_DISC_BLANK; + d->current_profile = 0; /* MMC reserved */ + strcpy(d->current_profile_text,"stdio file"); + d->current_is_cd_profile = 0; + d->current_is_supported_profile = 1; + d->block_types[BURN_WRITE_TAO] = BURN_BLOCK_MODE1; + d->block_types[BURN_WRITE_SAO] = BURN_BLOCK_MODE1; + } + + *drive_infos = calloc(2, sizeof(struct burn_drive_info)); + if (*drive_infos == NULL) + goto ex; + (*drive_infos)[0].drive = d; + (*drive_infos)[1].drive = NULL; /* End-Of-List mark */ + (*drive_infos)[0].tao_block_types = d->block_types[BURN_WRITE_TAO]; + (*drive_infos)[0].sao_block_types = d->block_types[BURN_WRITE_SAO]; + + d->released = 0; + ret = 1; +ex:; + if (ret <= 0 && d != NULL) { + burn_drive_free_subs(d); + free((char *) d); + } + return ret; +} + + +/* ts A70903 : API */ +int burn_drive_get_drive_role(struct burn_drive *d) +{ + return d->drive_role; +} + diff --git a/libburn/libburn.h b/libburn/libburn.h index 17c6d2b..0d014a3 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -1302,7 +1302,7 @@ struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size); /* ts A70328 */ /** Sets a fixed track size after the data source object has already been created. - @param t The track to poperate on + @param t The track to operate on @param size the number of bytes to use as track size @return <=0 indicates failure , >0 success */ @@ -1901,6 +1901,40 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, char data[], off_t data_size, off_t *data_count, int flag); +/* ts A70903 */ +/** Create and aquire a pseudo-drive which will accept option settings much + like a MMC burner drive. Many of them will not cause any effect, though. + There are two kinds of pseudo-drives: stdio-drives and null-drives. + A stdio-drive performs all its eventual data transfer activities on a file + via standard i/o functions open(2), lseek(2), read(2), write(2), close(2). + Its capabilities resemble DVD-RAM but the media profile reported is 0x00 + and it issues no realistic write space information. + A null-drive is created if the parameter "name" is an empty string. It will + pretend to have loaded no media. + @param drive_infos On success returns a one element array with the drive + (cdrom/burner). Thus use with driveno 0 only. On failure + the array has no valid elements at all. + The returned array should be freed via burn_drive_info_free() + when it is no longer needed. + @param name Sets the file address to be used for writing. Permissible + file types are regular file or block device. If the file + does not exist, it is attempted to create it as regular file. + An empty fname creates a null-drive. + @return 1 success , <=0 failure +*/ +int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname); + + +/** Inquire wether the drive object is a real MMC drive or a pseudo-drive + created by burn_drive_dummy(). + @param d The drive to inquire + @return 0= null-drive + 1= real MMC drive + 2= stdio-drive +*/ +int burn_drive_get_drive_role(struct burn_drive *d); + + #ifndef DOXYGEN BURN_END_DECLS diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index dca2457..3f23fe1 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -377,6 +377,11 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x00020143 (SORRY,HIGH) = Read start address not properly aligned 0x00020144 (SORRY,HIGH) = SCSI error on read 0x00020145 (FATAL,HIGH) = Drive is busy on attempt to read data + 0x00020146 (FATAL,HIGH) = Drive is a virtual placeholder + 0x00020147 (SORRY,HIGH) = Cannot address start byte + 0x00020148 (SORRY,HIGH) = Cannot write desired amount of data + 0x00020149 (SORRY,HIGH) = Unsuitable filetype for pseudo-drive + 0x0002014a (SORRY,HIGH) = Cannot read desired amount of data libdax_audioxtr: diff --git a/libburn/options.c b/libburn/options.c index ce374e4..4dc1ef3 100644 --- a/libburn/options.c +++ b/libburn/options.c @@ -142,6 +142,8 @@ int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim) int burn_write_opts_set_underrun_proof(struct burn_write_opts *opts, int underrun_proof) { + if (!opts->drive->mdata->valid) + return 0; if (opts->drive->mdata->underrun_proof) { opts->underrun_proof = underrun_proof; return 1; diff --git a/libburn/read.c b/libburn/read.c index 8feab8d..f2f1196 100644 --- a/libburn/read.c +++ b/libburn/read.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include + #include "sector.h" #include "libburn.h" #include "drive.h" @@ -288,12 +291,37 @@ static void flipq(unsigned char *sub) */ +/* ts A70904 */ +/** @param flag bit=be silent on data shortage */ +int burn_stdio_read(int fd, char *buf, int bufsize, struct burn_drive *d, + int flag) +{ + int todo, count = 0; + + for(todo = bufsize; todo > 0; ) { + count = read(fd, buf + (bufsize - todo), todo); + if(count <= 0) + break; + todo -= count; + } + if(todo > 0 && !(flag & 1)) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x0002014a, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Cannot read desired amount of data", errno, 0); + } + if (count < 0) + return -1; + return (bufsize - todo); +} + + /* ts A70812 : API function */ int burn_read_data(struct burn_drive *d, off_t byte_address, char data[], off_t data_size, off_t *data_count, int flag) { int alignment = 2048, start, upto, chunksize = 1, err, cpy_size, i; - int sose_mem = 0; + int sose_mem = 0, fd = -1, ret; char msg[81], *wpt; struct buffer buf; @@ -307,6 +335,13 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, "Drive is not grabbed on random access write", 0, 0); return 0; } + if (d->drive_role == 0) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020146, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Drive is a virtual placeholder (null-drive)", 0, 0); + return 0; + } if ((byte_address % alignment) != 0) { sprintf(msg, "Read start address not properly aligned (%d bytes)", @@ -325,6 +360,33 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, "Drive is busy on attempt to read data", 0, 0); return 0; } + + if (d->drive_role != 1) { + +/* <<< We need _LARGEFILE64_SOURCE defined by the build system. +*/ +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + + fd = open(d->devname, O_RDONLY | O_LARGEFILE); + if (fd == -1) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020005, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Failed to open device (a pseudo-drive)", + errno, 0); + ret = 0; goto ex; + } + if (lseek(fd, byte_address, SEEK_SET) == -1) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020147, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Cannot address start byte", errno, 0); + ret = 0; goto ex; + } + } + d->busy = BURN_DRIVE_READING_SYNC; d->buffer = &buf; @@ -342,7 +404,14 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, cpy_size = data_size - *data_count; if (flag & 2) d->silent_on_scsi_error = 1; - err = d->read_10(d, start, chunksize, d->buffer); + if (d->drive_role == 1) { + err = d->read_10(d, start, chunksize, d->buffer); + } else { + ret = burn_stdio_read(fd, (char *) d->buffer->data, + cpy_size, d, 0); + if (ret <= 0) + err = BE_CANCELLED; + } if (flag & 2) d->silent_on_scsi_error = sose_mem; if (err == BE_CANCELLED) { @@ -350,7 +419,16 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, for (i = 0; i < chunksize - 1; i++) { if (flag & 2) d->silent_on_scsi_error = 1; - err = d->read_10(d, start + i, 1, d->buffer); + if (d->drive_role == 1) { + err = d->read_10(d, start + i, 1, + d->buffer); + } else { + ret = burn_stdio_read(fd, + (char *) d->buffer->data, + 2048, d, 1); + if (ret <= 0) + err = BE_CANCELLED; + } if (flag & 2) d->silent_on_scsi_error = sose_mem; if (err == BE_CANCELLED) @@ -359,16 +437,18 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, wpt += 2048; *data_count += 2048; } - d->buffer = NULL; - d->busy = BURN_DRIVE_IDLE; - return 0; + ret = 0; goto ex; } memcpy(wpt, d->buffer->data, cpy_size); wpt += cpy_size; *data_count += cpy_size; } + ret = 1; +ex:; + if (fd != -1) + close(fd); d->buffer = NULL; d->busy = BURN_DRIVE_IDLE; - return 1; + return ret; } diff --git a/libburn/spc.c b/libburn/spc.c index 495d8a7..7fa1569 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -739,11 +739,8 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no, d->silent_on_scsi_error = 0; - d->idata = malloc(sizeof(struct burn_scsi_inquiry_data)); - d->idata->valid = 0; - d->mdata = malloc(sizeof(struct scsi_mode_data)); - d->mdata->valid = 0; - d->mdata->speed_descriptors = NULL; + d->idata = calloc(1, sizeof(struct burn_scsi_inquiry_data)); + d->mdata = calloc(1, sizeof(struct scsi_mode_data)); /* ts A61007 : obsolete Assert in drive_getcaps() */ if(d->idata == NULL || d->mdata == NULL) { @@ -752,6 +749,9 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no, "Could not allocate new drive object", 0, 0); return -1; } + d->idata->valid = 0; + d->mdata->valid = 0; + d->mdata->speed_descriptors = NULL; if(!(flag & 1)) { ret = spc_setup_drive(d); if (ret<=0) diff --git a/libburn/transport.h b/libburn/transport.h index 37dadae..7600160 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -121,6 +121,9 @@ struct burn_format_descr { /** Gets initialized in enumerate_common() and burn_drive_register() */ struct burn_drive { + /* ts A70902: 0=null-emulation , 1=MMC drive , 2=stdio-emulation */ + int drive_role; + int bus_no; int host; int id; diff --git a/libburn/write.c b/libburn/write.c index 175ac1f..8aafdff 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -18,11 +18,15 @@ #define Libburn_sao_can_appenD 1 */ - +#include #include #include #include #include +#include +#include +#include + #include "error.h" #include "sector.h" #include "libburn.h" @@ -910,6 +914,13 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc, reason_pt= reasons; reasons[0] = 0; + if (d->drive_role == 0) { + sprintf(reasons, + "DRIVE: is a virtual placeholder (null-drive)"); + no_media = 1; + goto ex; + } + /* check write mode against write job */ wt = burn_write_opts_auto_write_type(o, disc, reasons, 1); if (wt == BURN_WRITE_NONE) { @@ -922,16 +933,18 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc, reason_pt= reasons + strlen(reasons); if (d->status == BURN_DISC_UNSUITABLE) goto unsuitable_profile; - if (d->current_profile == 0x09 || d->current_profile == 0x0a) { + if (d->drive_role == 2 || + d->current_profile == 0x1a || d->current_profile == 0x12) { + /* DVD+RW , DVD-RAM , emulated drive on stdio file */ + if (o->start_byte >= 0 && (o->start_byte % 2048)) + strcat(reasons, + "write start address not properly aligned to 2048, "); + } else if (d->current_profile == 0x09 || d->current_profile == 0x0a) { + /* CD-R , CD-RW */ if (!burn_disc_write_is_ok(o, disc, (!!silent) << 1)) strcat(reasons, "unsuitable track mode found, "); if (o->start_byte >= 0) strcat(reasons, "write start address not supported, "); - } else if (d->current_profile == 0x1a || d->current_profile == 0x12) { - /* DVD+RW , DVD-RAM */ - if (o->start_byte >= 0 && (o->start_byte % 2048)) - strcat(reasons, - "write start address not properly aligned to 2048, "); } else if (d->current_profile == 0x13) { /* DVD-RW Restricted Overwrite */ if (o->start_byte >= 0 && (o->start_byte % 32768)) @@ -1431,8 +1444,6 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, /* >>> perform OPC if needed */; - /* >>> */; - return 1; } @@ -1743,6 +1754,177 @@ early_failure:; } +/* ts A70904 */ +int burn_stdio_open_write(struct burn_drive *d, off_t start_byte, int flag) +{ + int fd = -1; + int mode = O_RDWR | O_CREAT; + char msg[160]; + +/* <<< We need _LARGEFILE64_SOURCE defined by the build system. +*/ +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + + if (d->devname[0] == 0) /* null drives should not come here */ + return -1; + fd = open(d->devname, mode, S_IRUSR | S_IWUSR); + if (fd == -1) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020005, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Failed to open device (a pseudo-drive)", errno, 0); + } + if (start_byte < 0) + start_byte = 0; + if (lseek(fd, start_byte, SEEK_SET)==-1) { + sprintf(msg, "Cannot address start byte %.f", + (double) start_byte); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020147, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, errno, 0); + close(fd); + fd = -1; + } + d->nwa = start_byte / 2048; + return fd; +} + + +/* ts A70904 */ +int burn_stdio_read_source(struct burn_source *source, char *buf, int bufsize, + struct burn_write_opts *o, int flag) +{ + int count= 0, todo; + + for(todo = bufsize; todo > 0; todo -= count) { + count = source->read(source, + (unsigned char *) (buf + (bufsize - todo)), todo); + if (count <= 0) + break; + } + return (bufsize - todo); +} + + +/* ts A70904 */ +int burn_stdio_write(int fd, char *buf, int count, struct burn_drive *d, + int flag) +{ + if (write(fd, buf, count) != count) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020148, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Cannot write desired amount of data", errno, 0); + return 0; + } + return count; +} + + +/* ts A70904 */ +int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s, + int tnum, int fd, int flag) +{ + int open_ended, bufsize, ret, eof_seen = 0, sectors; + struct burn_track *t = s->track[tnum]; + struct burn_drive *d = o->drive; + off_t t_size, w_count; + char buf[16*2048]; + + bufsize = sizeof(buf); + + sectors = burn_track_get_sectors(t); + burn_disc_init_track_status(o, s, tnum, sectors); + + /* >>> write t->offset zeros */; + + open_ended = burn_track_is_open_ended(t); + t_size = t->source->get_size(t->source); + for(w_count = 0; w_count < t_size || open_ended; w_count += ret) { + + + if (t_size - w_count < bufsize && ! open_ended) + + /* >>> what about final sector padding ? */ + + bufsize = t_size - w_count; + if (eof_seen) + ret = 0; + else + ret = burn_stdio_read_source(t->source, buf, + bufsize, o, 0); + if (ret < 0) + return ret; + if (ret == 0 && open_ended) + break; + if (ret < bufsize && !open_ended) { + memset(buf + ret, 0, bufsize - ret); + eof_seen = 1; + ret = bufsize; + } + ret = burn_stdio_write(fd, buf, ret, d, 0); + if (ret <= 0) + return ret; + + d->progress.sector = (w_count + (off_t) ret) / (off_t) 2048; + if (open_ended) + d->progress.sectors = d->progress.sector; + } + + /* >>> write t->tail zeros */; + + return 1; +} + + +/* ts A70904 */ +int burn_stdio_write_sync(struct burn_write_opts *o, + struct burn_disc *disc) +{ + int ret, fd = -1; + struct burn_drive *d = o->drive; + + d->needs_close_session = 0; + o->obs_pad = 0; /* no filling-up of track's last 32k buffer */ + o->obs = 32*1024; /* buffer size */ + + if (disc->sessions != 1) + {ret= 0 ; goto ex;} + if (disc->session[0]->tracks != 1) + {ret= 0 ; goto ex;} + + /* update progress */ + d->progress.session = 0; + d->progress.tracks = 1; + + /* open target file */ + fd = burn_stdio_open_write(d, o->start_byte, 0); + if (fd == -1) + {ret = 0; goto ex;} + + ret = burn_stdio_write_track(o, disc->session[0], 0, fd, 0); + if (ret <= 0) + goto ex; + + /* XXX: currently signs an end of session */ + d->progress.sector = 0; + d->progress.start_sector = 0; + d->progress.sectors = 0; + ret = 1; +ex:; + if (fd != -1) + close (fd); + /* update media state records */ + burn_drive_mark_unready(d); + + d->busy = BURN_DRIVE_IDLE; + return ret; +} + + void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc) { struct cue_sheet *sheet; @@ -1765,6 +1947,13 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc) d->rlba = -150; d->toc_temp = 9; + /* ts A70904 */ + if (d->drive_role != 1) { + ret = burn_stdio_write_sync(o, disc); + if (ret <= 0) + goto fail_wo_sync; + return; + } /* ts A61218 */ if (! d->current_is_cd_profile) { ret = burn_dvd_write_sync(o, disc); @@ -1974,7 +2163,7 @@ fail_wo_sync:; int burn_random_access_write(struct burn_drive *d, off_t byte_address, char *data, off_t data_count, int flag) { - int alignment = 0, start, upto, chunksize, err; + int alignment = 0, start, upto, chunksize, err, fd = -1, ret; char msg[81], *rpt; struct buffer buf; @@ -1985,6 +2174,16 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, "Drive is not grabbed on random access write", 0, 0); return 0; } + if(d->drive_role == 0) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020146, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Drive is a virtual placeholder (null-drive)", 0, 0); + return 0; + } + + if(d->drive_role != 1) + alignment = 2 * 1024; if (d->current_profile == 0x12) /* DVD-RAM */ alignment = 2 * 1024; if (d->current_profile == 0x13) /* DVD-RW restricted overwrite */ @@ -2019,7 +2218,6 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, msg, 0, 0); return 0; } - if (d->busy != BURN_DRIVE_IDLE) { libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020140, @@ -2027,6 +2225,11 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, "Drive is busy on attempt to write random access",0,0); return 0; } + if(d->drive_role != 1) { + fd = burn_stdio_open_write(d, byte_address, 0); + if (fd == -1) + return 0; + } d->busy = BURN_DRIVE_WRITING_SYNC; d->buffer = &buf; @@ -2042,15 +2245,26 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, rpt += d->buffer->bytes; d->buffer->sectors = chunksize; d->nwa = start; - err = d->write(d, d->nwa, d->buffer); + if(d->drive_role == 1) { + err = d->write(d, d->nwa, d->buffer); + } else { + ret = burn_stdio_write(fd, (char *) d->buffer->data, + d->buffer->bytes, d, 0); + if (ret <= 0) + err = BE_CANCELLED; + } if (err == BE_CANCELLED) { d->busy = BURN_DRIVE_IDLE; + if(fd != -1) + close(fd); return (-(start * 2048 - byte_address)); } } - if (flag & 1) + if(d->drive_role == 1 && (flag & 1)) d->sync_cache(d); + if(fd != -1) + close(fd); d->buffer = NULL; d->busy = BURN_DRIVE_IDLE; return 1;