diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 8df286f..f5ebc7a 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2011.03.12.093520" +#define Cdrskin_timestamP "2011.03.13.130746" diff --git a/libburn/async.c b/libburn/async.c index 3e41e1c..09526d3 100644 --- a/libburn/async.c +++ b/libburn/async.c @@ -659,6 +659,14 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) "Drive is a virtual placeholder (null-drive)", 0, 0); return; } + if (d->drive_role == 4) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020181, + LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH, + "Pseudo-drive is a read-only file. Cannot write.", + 0, 0); + return; + } /* ts A61007 : obsolete Assert in spc_select_write_params() */ if (d->drive_role == 1 && d->mdata->valid <= 0) { diff --git a/libburn/drive.c b/libburn/drive.c index f92f7f6..5d947c9 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -60,6 +60,10 @@ static int drivetop = -1; /* ts A80410 : in init.c */ extern int burn_support_untested_profiles; +/* ts B10312 : in init.c */ +extern int burn_drive_role_4_allowed; + + /* ts A61021 : the unspecific part of sg.c:enumerate_common() */ int burn_setup_drive(struct burn_drive *d, char *fname) @@ -1386,6 +1390,7 @@ static int burn_drive__is_rdwr(char *fname, int *stat_ret, read_size = (off_t) 0x7ffffff0 * (off_t) 2048; } } + if (is_rdwr && fd >= 0) { getfl_ret = fcntl(fd, F_GETFL); @@ -1411,6 +1416,37 @@ fprintf(stderr, "LIBBURN_DEBUG: burn_drive__is_rdwr: getfl_ret = %lX , O_RDWR = } +static int burn_role_by_access(char *fname, int flag) +{ +/* We normally need _LARGEFILE64_SOURCE defined by the build system. + Nevertheless the system might use large address integers by default. +*/ +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + int fd; + + fd = open(fname, O_RDWR | O_LARGEFILE); + if (fd != -1) { + close(fd); + return 2; + } + fd = open(fname, O_RDONLY | O_LARGEFILE); + if (fd != -1) { + close(fd); + return 4; + } + fd = open(fname, O_WRONLY | O_LARGEFILE); + if (fd != -1) { + close(fd); + return 3; + } + if (flag & 1) + return 0; + return 2; +} + + /* ts A70903 : Implements adquiration of pseudo drives */ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) { @@ -1422,8 +1458,6 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) struct burn_drive *d= NULL, *regd_d; struct stat stbuf; - static int allow_role_3 = 1; - if (fname[0] != 0) { is_rdwr = burn_drive__is_rdwr(fname, &stat_ret, &stbuf, &read_size, 1); @@ -1445,22 +1479,18 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) return 0; } if (fname[0] != 0) { - - /* >>> as soon as new role 4 is introduced: - if (is_rdwr == 2) role = 4; else - */ - - role = 2; + if (is_rdwr == 2 && + (burn_drive_role_4_allowed & 1)) + role = 4; + else + role = 2; + if (stat_ret != -1 && is_rdwr == 1 && + (burn_drive_role_4_allowed & 3) == 3) + role = burn_role_by_access(fname, + !!(burn_drive_role_4_allowed & 4)); } else role = 0; } else { - if(S_ISDIR(stbuf.st_mode) || !allow_role_3) { - libdax_msgs_submit(libdax_messenger, -1, - 0x00020149, - LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - "Unsuitable filetype for pseudo-drive", 0, 0); - return 0; - } role = 3; } } @@ -1481,22 +1511,28 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) } free((char *) d); /* all sub pointers have been copied to *regd_d */ d = regd_d; - if (d->drive_role == 2 || d->drive_role == 3) { - d->status = BURN_DISC_BLANK; - d->current_profile = 0xffff; /* MMC for non-compliant drive */ + if (d->drive_role == 2 || d->drive_role == 3 || d->drive_role == 4) { + if (d->drive_role == 4) { + d->status = BURN_DISC_FULL; + /* MMC for non-compliant drive */ + d->current_profile = 0xffff; + d->block_types[BURN_WRITE_TAO] = 0; + d->block_types[BURN_WRITE_SAO] = 0; + } else { + d->status = BURN_DISC_BLANK; + /* MMC for non-compliant drive */ + d->current_profile = 0xffff; + d->block_types[BURN_WRITE_TAO] = BURN_BLOCK_MODE1; + d->block_types[BURN_WRITE_SAO] = BURN_BLOCK_SAO; + } 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_SAO; if (read_size >= 0) /* despite its name : last valid address, not size */ d->media_read_capacity = read_size / 2048 - !(read_size % 2048); burn_drive_set_media_capacity_remaining(d, size); - - /* >>> ? open file for a test ? (>>> beware of "-" = stdin) */; - } else d->current_profile = 0; /* Drives return this if empty */ @@ -1515,6 +1551,10 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) strcpy((*drive_infos)[0].vendor,"YOYODYNE"); strcpy((*drive_infos)[0].product,"BLACKHOLE"); strcpy((*drive_infos)[0].revision,"FX02"); + } else if (d->drive_role == 4) { + strcpy((*drive_infos)[0].vendor,"YOYODYNE"); + strcpy((*drive_infos)[0].product,"WARP DRIVE"); + strcpy((*drive_infos)[0].revision,"FX03"); } else { strcpy((*drive_infos)[0].vendor,"FERENGI"); strcpy((*drive_infos)[0].product,"VAPORWARE"); @@ -2448,7 +2488,7 @@ 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 (d->drive_role == 0) + if (d->drive_role == 0 || d->drive_role == 4) return 0; if (d->drive_role == 2) { /* stdio file drive : random access read-write */ @@ -2711,12 +2751,9 @@ int burn_drive_equals_adr(struct burn_drive *d1, char *adr2_in, int role2) if (fd != -1) exact_role_matters = 1; ret = burn_drive__is_rdwr(adr2, NULL, NULL, NULL, 1); - - /* >>> as soon as new role 4 is introduced: - if (ret == 2) role2 = 4; else - */ - - if (ret == 1) + if (ret == 2 && burn_drive_role_4_allowed) + role2 = 4; + else if (ret > 0) role2 = 2; else role2 = 3; diff --git a/libburn/init.c b/libburn/init.c index 64ae3f2..9977842 100644 --- a/libburn/init.c +++ b/libburn/init.c @@ -105,6 +105,14 @@ int burn_support_untested_profiles = 0; */ int burn_sg_log_scsi = 0; + +/* ts B10312 : + Whether to map random-access readonly files to drive role 4. + Else it is role 2 overwriteable drive +*/ +int burn_drive_role_4_allowed = 0; + + /* ts A60925 : ticket 74 */ /** Create the messenger object for libburn. */ int burn_msgs_initialize(void) @@ -565,3 +573,10 @@ void burn_set_scsi_logging(int flag) { burn_sg_log_scsi = flag & 7; } + + +/* ts B10312 API */ +void burn_allow_drive_role_4(int allowed) +{ + burn_drive_role_4_allowed = (allowed & 7); +} diff --git a/libburn/libburn.h b/libburn/libburn.h index 72e6b66..9c22f20 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -3004,7 +3004,7 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, char data[], off_t data_size, off_t *data_count, int flag); -/* A70904 */ +/* ts A70904 */ /** Inquire whether the drive object is a real MMC drive or a pseudo-drive created by a stdio: address. @param d The drive to inquire @@ -3012,11 +3012,41 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, 1= real MMC drive 2= stdio-drive, random access, read-write 3= stdio-drive, sequential, write-only + 4= stdio-drive, random access, read-only + (only if enabled by burn_allow_drive_role_4()) @since 0.4.0 */ int burn_drive_get_drive_role(struct burn_drive *d); +/* ts B10312 */ +/** Allow drive role 4 "random access read-only" drive. + By default a random access file assumes drive role 2 "read-write" + regardless whether it is actually readable or writeable. + If enabled, random-access file objects which recognizably allow no + writing will be classified as role 4. + Candidates are drive addresses of the form stdio:/dev/fd/# , where # is + the integer number of an open file descriptor. If this descriptor was + opened read-only, then it gets role 4. + Other paths may get tested by an attempt to open them for read-write + (role 2) resp. read-only (role 4) resp. write-only (role 3). See bit1. + read-only + @param allowed Bitfield for control purposes: + bit0= Enable role 4 for drives which get aquired + after this call + bit1= with bit0: + Test whether the file can be opened for + read-write resp. read-only resp. write-only. + Classify as roles 2 resp. 4 resp. 3. + bit2= with bit0 and bit1: + Classify files which cannot be opened at all + as role 0 : useless dummy. + Else classify as role 2. + @since 1.0.6 +*/ +void burn_allow_drive_role_4(int allowed); + + /* ts A70923 */ /** Find out whether a given address string would lead to the given drive object. This should be done in advance for track source addresses diff --git a/libburn/libburn.ver b/libburn/libburn.ver index e0a1c01..c634773 100644 --- a/libburn/libburn.ver +++ b/libburn/libburn.ver @@ -2,6 +2,7 @@ LIBBURN4 { global: burn_abort; burn_abort_pacifier; +burn_allow_drive_role_4; burn_allow_untested_profiles; burn_disc_add_session; burn_disc_available_space; diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index 4f2987d..30c9c56 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -566,6 +566,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x0002017e (FAILURE,HIGH) = Failed to close track, session, or disc 0x0002017f (FAILURE,HIGH) = Failed to synchronize drive cache 0x00020180 (FAILURE,HIGH) = Premature end of input encountered + 0x00020181 (FAILURE,HIGH) = Pseudo-drive is a read-only file. Cannot write. libdax_audioxtr: 0x00020200 (SORRY,HIGH) = Cannot open audio source file diff --git a/libburn/write.c b/libburn/write.c index 025f6fc..66e0984 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -1005,9 +1005,12 @@ 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)"); + if (d->drive_role == 0 || d->drive_role == 4) { + if (d->drive_role == 0) + sprintf(reasons, + "DRIVE: is a virtual placeholder (null-drive)"); + else + sprintf(reasons, "DRIVE: read-only pseudo drive"); no_media = 1; goto ex; } @@ -2042,6 +2045,14 @@ int burn_stdio_open_write(struct burn_drive *d, off_t start_byte, char msg[160]; off_t lseek_res; + if(d->drive_role == 4) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020181, + LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH, + "Pseudo-drive is a read-only file. Cannot write.", + 0, 0); + return 0; + } if (d->devname[0] == 0) /* null drives should not come here */ return -1; fd = burn_drive__fd_from_special_adr(d->devname); @@ -2421,6 +2432,14 @@ calloc() seems not to have the desired effect. valgrind warns: d->rlba = -150; d->toc_temp = 9; + if(d->drive_role == 4) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020181, + LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH, + "Pseudo-drive is a read-only file. Cannot write.", + 0, 0); + goto fail_wo_sync; + } /* ts A70904 */ if (d->drive_role != 1) { ret = burn_stdio_write_sync(o, disc); @@ -2644,6 +2663,14 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, "Drive is a virtual placeholder (null-drive)", 0, 0); return 0; } + if(d->drive_role == 4) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020181, + LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH, + "Pseudo-drive is a read-only file. Cannot write.", + 0, 0); + return 0; + } if(d->drive_role == 2) alignment = 2 * 1024;