From 5e995c9cd000c3beb238926e7031c7dd8dbdc314 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Mon, 24 Sep 2007 13:54:52 +0000 Subject: [PATCH] Implemented drive role 3, sequential write-only stdio drives (e.g. stdout) --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 80 ++++++++++++++++++++++++++++--------- libburn/drive.h | 7 ++++ libburn/libburn.h | 49 +++++++++++++++++------ libburn/read.c | 8 +++- libburn/transport.h | 7 +++- libburn/write.c | 50 +++++++++++++---------- 7 files changed, 149 insertions(+), 54 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 35f4cf2..4e1dcdc 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2007.09.24.062354" +#define Cdrskin_timestamP "2007.09.24.135440" diff --git a/libburn/drive.c b/libburn/drive.c index 95c04b9..ecaad47 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -262,7 +262,7 @@ int burn_drive_grab(struct burn_drive *d, int le) } if(d->drive_role != 1) { d->released = 0; - if(d->drive_role == 2) { + if(d->drive_role == 2 || d->drive_role == 3) { d->status = BURN_DISC_BLANK; d->current_profile = 0xffff; } else { @@ -1118,18 +1118,42 @@ int burn_drive_is_banned(char *device_address) } -/* ts A70903 : will vanish from API */ +/* ts A70924 */ +int burn_drive__fd_from_special_adr(char *adr) +{ + int fd = -1, i; + + if (strcmp(adr, "-") == 0) + fd = 1; + if(strncmp(adr, "/dev/fd/", 8) == 0) { + for (i = 8; adr[i]; i++) + if (!isdigit(adr[i])) + break; + if (i> 8 && adr[i] == 0) + fd = atoi(adr + 8); + } + return fd; +} + + +/* ts A70903 : Implements adquiration of pseudo drives */ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) { - int ret; + int ret = -1, fd = -1, role = 0; off_t size = ((off_t) (1024 * 1024 * 1024) * (off_t) 2048); struct burn_drive *d= NULL, *regd_d; struct stat stbuf; + static int allow_role_3 = 1; + if (fname[0] != 0) { memset(&stbuf, 0, sizeof(stbuf)); - ret = stat(fname, &stbuf); - if(ret == -1 || S_ISBLK(stbuf.st_mode) || + fd = burn_drive__fd_from_special_adr(fname); + if (fd >= 0) + ret = fstat(fd, &stbuf); + else + ret = stat(fname, &stbuf); + if (ret == -1 || S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) { ret = burn_os_stdio_capacity(fname, &size); if (ret == -1) { @@ -1147,12 +1171,19 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) errno, 0); return 0; } + if (fname[0] != 0) + role = 2; + else + role = 0; } else { - libdax_msgs_submit(libdax_messenger, -1, - 0x00020149, - LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - "Unsuitable filetype for pseudo-drive", 0, 0); - return 0; + 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; } } d= (struct burn_drive *) calloc(1, sizeof(struct burn_drive)); @@ -1161,10 +1192,7 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) burn_setup_drive(d, fname); d->status = BURN_DISC_EMPTY; - if (fname[0] != 0) - d->drive_role = 2; - else - d->drive_role = 0; + d->drive_role = role; ret = burn_scsi_setup_drive(d, -1, -1, -1, -1, -1, 0); if (ret <= 0) goto ex; @@ -1175,7 +1203,7 @@ 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) { + if (d->drive_role == 2 || d->drive_role == 3) { d->status = BURN_DISC_BLANK; d->current_profile = 0xffff; /* MMC for non-compliant drive */ strcpy(d->current_profile_text,"stdio file"); @@ -1185,7 +1213,7 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname) d->block_types[BURN_WRITE_SAO] = BURN_BLOCK_SAO; d->media_capacity_remaining = size; - /* >>> ? open file for a test ? */; + /* >>> ? open file for a test ? (>>> beware of "-" = stdin) */; } else d->current_profile = 0; /* Drives return this if empty */ @@ -1201,6 +1229,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,"WARP DRIVE"); strcpy((*drive_infos)[0].revision,"FX01"); + } else if (d->drive_role == 3) { + strcpy((*drive_infos)[0].vendor,"YOYODYNE"); + strcpy((*drive_infos)[0].product,"BLACKHOLE"); + strcpy((*drive_infos)[0].revision,"FX02"); } else { strcpy((*drive_infos)[0].vendor,"FERENGI"); strcpy((*drive_infos)[0].product,"VAPORWARE"); @@ -1780,7 +1812,7 @@ off_t burn_disc_available_space(struct burn_drive *d, return 0; if (d->drive_role == 0) return 0; - if (d->drive_role == 2) { + if (d->drive_role != 1) { if (d->media_capacity_remaining <= 0) d->media_capacity_remaining = ((off_t) (1024 * 1024 * 1024) * (off_t) 2048); @@ -2011,7 +2043,7 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt, if (d->drive_role == 0) return 0; if (d->drive_role == 2) { - /* stdio file dummy drive */ + /* stdio file drive : random access read-write */ o->start_adr = 1; size = d->media_capacity_remaining; burn_os_stdio_capacity(d->devname, &size); @@ -2022,6 +2054,12 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt, o->might_do_tao = 2; o->advised_write_mode = BURN_WRITE_TAO; o->might_simulate = 1; + } else if (d->drive_role != 1) { + /* stdio file drive : sequential access write-only */ + o->might_do_sao = 4; + o->might_do_tao = 2; + o->advised_write_mode = BURN_WRITE_TAO; + o->might_simulate = 1; } else if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) { return 0; } else if (s == BURN_DISC_APPENDABLE && @@ -2251,6 +2289,12 @@ int burn_drive_equals_adr(struct burn_drive *d1, char *adr2_in, int role2) stat_ret2 = stat(adr2, &stbuf2); conv_ret2 = burn_drive_convert_fs_adr(adr2, conv_adr2); + /* roles 2 and 3 have the same name space and object interpretation */ + if (role1 == 3) + role1 = 2; + if (role2 == 3) + role2 = 2; + if (strcmp(adr1, adr2) == 0 && role1 == role2) return(1); /* equal role and address */ if (role1 == 1 && role2 == 1) { diff --git a/libburn/drive.h b/libburn/drive.h index 18b426b..640960f 100644 --- a/libburn/drive.h +++ b/libburn/drive.h @@ -114,4 +114,11 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc, struct burn_write_opts *opts, struct burn_disc_mode_demands *result, int flag); + +/* ts A70924 : convert a special stdio address into fd number. + @return >0 is a valid fd , -1 indicates unsuitable address string. +*/ +int burn_drive__fd_from_special_adr(char *adr); + + #endif /* __DRIVE */ diff --git a/libburn/libburn.h b/libburn/libburn.h index 00345eb..de12042 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -622,9 +622,11 @@ void burn_allow_untested_profiles(int yes); /* ts A60823 */ -/** Aquire a drive with known persistent address. This is the sysadmin friendly - way to open one drive and to leave all others untouched. It bundles - the following API calls to form a non-obtrusive way to use libburn: +/** Aquire a drive with known persistent address. + + This is the sysadmin friendly way to open one drive and to leave all + others untouched. It bundles the following API calls to form a + non-obtrusive way to use libburn: burn_drive_add_whitelist() , burn_drive_scan() , burn_drive_grab() You are *strongly urged* to use this call whenever you know the drive address in advance. @@ -639,28 +641,48 @@ void burn_allow_untested_profiles(int yes); Another way is to drop the unwanted drives by burn_drive_info_forget(). Operating on multiple drives: + Different than with burn_drive_scan() it is allowed to call burn_drive_scan_and_grab() without giving up any other scanned drives. So this call can be used to get a collection of more than one aquired drives. The attempt to aquire the same drive twice will fail, though. Pseudo-drives: + burn_drive_scan_and_grab() is able to aquire virtual drives which will accept options much like a MMC burner drive. Many of those options will not cause any effect, though. The address of a pseudo-drive begins with - prefix "stdio:" optionally followed by the path to an existing regular - file, or to a not yet existing file, or to an existing block device. - Example: "stdio:/tmp/pseudo_drive" - If the path is empty then the resulting pseudo-drive is a null-drive. - A null-drive will pretend to have loaded no media and support no writing. - A pseudo-drive with a non-empty path is called a stdio-drive. - It will perform all its eventual data transfer activities on a file + prefix "stdio:" followed by a path. + Examples: "stdio:/tmp/pseudo_drive" , "stdio:/dev/null" , "stdio:-" + + If the path is empty, the result is a null-drive = drive role 0. + It pretends to have loaded no media and supports no reading or writing. + + If the path leads to an existing regular file, or to a not yet existing + file, or to an existing block device, then the result is a random access + stdio-drive capable of reading and writing = drive role 2. + + If the path leads to an existing file of any type other than directory, + then the result is a sequential write-only stdio-drive = drive role 3. + + The special address form "stdio:/dev/fd/" is interpreted literally + as reference to open file descriptor . This address form coincides + with real files on some systems, but it is in fact hardcoded in libburn. + Special address "stdio:-" means stdout = "stdio:/dev/fd/1". + The role of such a drive is determined by the file type obtained via + fstat(). + + Roles 2 and 3 perform all their 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 0xffff, - it can simulate writing and it issues no realistic write space information. + The media profile is reported as 0xffff. Write space information from those + media is not necessarily realistic. + + The capabilities of role 2 resemble DVD-RAM but it can simulate writing. If the path does not exist in the filesystem yet, it is attempted to create it as a regular file as soon as write operations are started. + The capabilities of role 3 resemble a blank DVD-R. + One may distinguish pseudo-drives from MMC drives by call burn_drive_get_drive_role(). @@ -2004,7 +2026,8 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, @param d The drive to inquire @return 0= null-drive 1= real MMC drive - 2= stdio-drive + 2= stdio-drive, random access, read-write + 3= stdio-drive, sequential, write-only */ int burn_drive_get_drive_role(struct burn_drive *d); diff --git a/libburn/read.c b/libburn/read.c index 378aa66..913533a 100644 --- a/libburn/read.c +++ b/libburn/read.c @@ -332,7 +332,7 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020142, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - "Drive is not grabbed on random access write", 0, 0); + "Drive is not grabbed on random access read", 0, 0); return 0; } if (d->drive_role == 0) { @@ -341,6 +341,12 @@ int burn_read_data(struct burn_drive *d, off_t byte_address, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, "Drive is a virtual placeholder (null-drive)", 0, 0); return 0; + } else if (d->drive_role == 3) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020151, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Read attempt on write-only drive", 0, 0); + return 0; } if ((byte_address % alignment) != 0) { sprintf(msg, diff --git a/libburn/transport.h b/libburn/transport.h index 25b79fb..5ae08d4 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -121,7 +121,12 @@ 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 */ + /* ts A70902: + 0=null-emulation + 1=MMC drive , + 2=stdio random read-write + 3=stdio sequential write-only + */ int drive_role; int bus_no; diff --git a/libburn/write.c b/libburn/write.c index 62cc063..5bc96bd 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -951,10 +951,11 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc, if (o->start_byte >= 0 && (o->start_byte % 32768)) strcat(reasons, "write start address not properly aligned to 32k, "); - } else if (d->current_profile == 0x11 || d->current_profile == 0x14 || + } else if (d->drive_role == 3 || + d->current_profile == 0x11 || d->current_profile == 0x14 || d->current_profile == 0x15 || d->current_profile == 0x1b || d->current_profile == 0x2b ) { - /* DVD-R* Sequential , DVD+R[/DL] */ + /* DVD-R* Sequential , DVD+R[/DL] , sequential stdio "drive" */ if (o->start_byte >= 0) strcat(reasons, "write start address not supported, "); } else { @@ -1624,26 +1625,33 @@ int burn_stdio_open_write(struct burn_drive *d, off_t start_byte, if (d->devname[0] == 0) /* null drives should not come here */ return -1; - fd = open(d->devname, mode, S_IRUSR | S_IWUSR); + fd = burn_drive__fd_from_special_adr(d->devname); + if (fd >= 0) + fd = dup(fd); /* check validity and make closeable */ + else + 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); + d->cancel = 1; return -1; } 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; - } + if (d->drive_role == 2) + 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); + d->cancel = 1; + fd = -1; + } d->nwa = start_byte / sector_size; return fd; } @@ -1761,6 +1769,8 @@ int burn_stdio_sync_cache(int fd, struct burn_drive *d, int flag) LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, "syncing cache (stdio fsync)", 0, 0); if (fsync(fd) != 0) { + if (errno == EINVAL) /* E.g. /dev/null cannot fsync */ + return 1; libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020148, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, @@ -1967,10 +1977,10 @@ int burn_stdio_write_sync(struct burn_write_opts *o, d->progress.sectors = 0; ret = 1; ex:; - if (d->stdio_fd != -1) { - close (d->stdio_fd); - d->stdio_fd = -1; - } + if (d->stdio_fd >= 0) + close(d->stdio_fd); + d->stdio_fd = -1; + /* update media state records */ burn_drive_mark_unready(d); @@ -2203,7 +2213,7 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, return 0; } - if(d->drive_role != 1) + if(d->drive_role == 2) alignment = 2 * 1024; if (d->current_profile == 0x12) /* DVD-RAM */ alignment = 2 * 1024; @@ -2277,7 +2287,7 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, } if (err == BE_CANCELLED) { d->busy = BURN_DRIVE_IDLE; - if(fd != -1) + if(fd >= 0) close(fd); return (-(start * 2048 - byte_address)); } @@ -2290,7 +2300,7 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address, burn_stdio_sync_cache(fd, d, 0); } - if(fd != -1) + if(fd >= 0) close(fd); d->buffer = NULL; d->busy = BURN_DRIVE_IDLE;