Implemented drive role 3, sequential write-only stdio drives (e.g. stdout)

This commit is contained in:
Thomas Schmitt 2007-09-24 13:54:52 +00:00
parent 83fe9f3621
commit 5e995c9cd0
7 changed files with 149 additions and 54 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2007.09.24.062354" #define Cdrskin_timestamP "2007.09.24.135440"

View File

@ -262,7 +262,7 @@ int burn_drive_grab(struct burn_drive *d, int le)
} }
if(d->drive_role != 1) { if(d->drive_role != 1) {
d->released = 0; d->released = 0;
if(d->drive_role == 2) { if(d->drive_role == 2 || d->drive_role == 3) {
d->status = BURN_DISC_BLANK; d->status = BURN_DISC_BLANK;
d->current_profile = 0xffff; d->current_profile = 0xffff;
} else { } 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 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); off_t size = ((off_t) (1024 * 1024 * 1024) * (off_t) 2048);
struct burn_drive *d= NULL, *regd_d; struct burn_drive *d= NULL, *regd_d;
struct stat stbuf; struct stat stbuf;
static int allow_role_3 = 1;
if (fname[0] != 0) { if (fname[0] != 0) {
memset(&stbuf, 0, sizeof(stbuf)); memset(&stbuf, 0, sizeof(stbuf));
ret = stat(fname, &stbuf); fd = burn_drive__fd_from_special_adr(fname);
if(ret == -1 || S_ISBLK(stbuf.st_mode) || 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)) { S_ISREG(stbuf.st_mode)) {
ret = burn_os_stdio_capacity(fname, &size); ret = burn_os_stdio_capacity(fname, &size);
if (ret == -1) { if (ret == -1) {
@ -1147,12 +1171,19 @@ int burn_drive_grab_dummy(struct burn_drive_info *drive_infos[], char *fname)
errno, 0); errno, 0);
return 0; return 0;
} }
if (fname[0] != 0)
role = 2;
else
role = 0;
} else { } else {
libdax_msgs_submit(libdax_messenger, -1, if(S_ISDIR(stbuf.st_mode) || !allow_role_3) {
0x00020149, libdax_msgs_submit(libdax_messenger, -1,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, 0x00020149,
"Unsuitable filetype for pseudo-drive", 0, 0); LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
return 0; "Unsuitable filetype for pseudo-drive", 0, 0);
return 0;
}
role = 3;
} }
} }
d= (struct burn_drive *) calloc(1, sizeof(struct burn_drive)); 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); burn_setup_drive(d, fname);
d->status = BURN_DISC_EMPTY; d->status = BURN_DISC_EMPTY;
if (fname[0] != 0) d->drive_role = role;
d->drive_role = 2;
else
d->drive_role = 0;
ret = burn_scsi_setup_drive(d, -1, -1, -1, -1, -1, 0); ret = burn_scsi_setup_drive(d, -1, -1, -1, -1, -1, 0);
if (ret <= 0) if (ret <= 0)
goto ex; 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 */ free((char *) d); /* all sub pointers have been copied to *regd_d */
d = 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->status = BURN_DISC_BLANK;
d->current_profile = 0xffff; /* MMC for non-compliant drive */ d->current_profile = 0xffff; /* MMC for non-compliant drive */
strcpy(d->current_profile_text,"stdio file"); 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->block_types[BURN_WRITE_SAO] = BURN_BLOCK_SAO;
d->media_capacity_remaining = size; d->media_capacity_remaining = size;
/* >>> ? open file for a test ? */; /* >>> ? open file for a test ? (>>> beware of "-" = stdin) */;
} else } else
d->current_profile = 0; /* Drives return this if empty */ 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].vendor,"YOYODYNE");
strcpy((*drive_infos)[0].product,"WARP DRIVE"); strcpy((*drive_infos)[0].product,"WARP DRIVE");
strcpy((*drive_infos)[0].revision,"FX01"); 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 { } else {
strcpy((*drive_infos)[0].vendor,"FERENGI"); strcpy((*drive_infos)[0].vendor,"FERENGI");
strcpy((*drive_infos)[0].product,"VAPORWARE"); strcpy((*drive_infos)[0].product,"VAPORWARE");
@ -1780,7 +1812,7 @@ off_t burn_disc_available_space(struct burn_drive *d,
return 0; return 0;
if (d->drive_role == 0) if (d->drive_role == 0)
return 0; return 0;
if (d->drive_role == 2) { if (d->drive_role != 1) {
if (d->media_capacity_remaining <= 0) if (d->media_capacity_remaining <= 0)
d->media_capacity_remaining = d->media_capacity_remaining =
((off_t) (1024 * 1024 * 1024) * (off_t) 2048); ((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) if (d->drive_role == 0)
return 0; return 0;
if (d->drive_role == 2) { if (d->drive_role == 2) {
/* stdio file dummy drive */ /* stdio file drive : random access read-write */
o->start_adr = 1; o->start_adr = 1;
size = d->media_capacity_remaining; size = d->media_capacity_remaining;
burn_os_stdio_capacity(d->devname, &size); 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->might_do_tao = 2;
o->advised_write_mode = BURN_WRITE_TAO; o->advised_write_mode = BURN_WRITE_TAO;
o->might_simulate = 1; 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) { } else if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) {
return 0; return 0;
} else if (s == BURN_DISC_APPENDABLE && } 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); stat_ret2 = stat(adr2, &stbuf2);
conv_ret2 = burn_drive_convert_fs_adr(adr2, conv_adr2); 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) if (strcmp(adr1, adr2) == 0 && role1 == role2)
return(1); /* equal role and address */ return(1); /* equal role and address */
if (role1 == 1 && role2 == 1) { if (role1 == 1 && role2 == 1) {

View File

@ -114,4 +114,11 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc,
struct burn_write_opts *opts, struct burn_write_opts *opts,
struct burn_disc_mode_demands *result, int flag); 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 */ #endif /* __DRIVE */

View File

@ -622,9 +622,11 @@ void burn_allow_untested_profiles(int yes);
/* ts A60823 */ /* ts A60823 */
/** Aquire a drive with known persistent address. This is the sysadmin friendly /** Aquire a drive with known persistent address.
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: 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() burn_drive_add_whitelist() , burn_drive_scan() , burn_drive_grab()
You are *strongly urged* to use this call whenever you know the drive You are *strongly urged* to use this call whenever you know the drive
address in advance. 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(). Another way is to drop the unwanted drives by burn_drive_info_forget().
Operating on multiple drives: Operating on multiple drives:
Different than with burn_drive_scan() it is allowed to call Different than with burn_drive_scan() it is allowed to call
burn_drive_scan_and_grab() without giving up any other scanned drives. So 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. 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. The attempt to aquire the same drive twice will fail, though.
Pseudo-drives: Pseudo-drives:
burn_drive_scan_and_grab() is able to aquire virtual drives which will 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 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 cause any effect, though. The address of a pseudo-drive begins with
prefix "stdio:" optionally followed by the path to an existing regular prefix "stdio:" followed by a path.
file, or to a not yet existing file, or to an existing block device. Examples: "stdio:/tmp/pseudo_drive" , "stdio:/dev/null" , "stdio:-"
Example: "stdio:/tmp/pseudo_drive"
If the path is empty then the resulting pseudo-drive is a null-drive. If the path is empty, the result is a null-drive = drive role 0.
A null-drive will pretend to have loaded no media and support no writing. It pretends to have loaded no media and supports no reading or 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 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/<number>" is interpreted literally
as reference to open file descriptor <number>. 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(<number>).
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). 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, The media profile is reported as 0xffff. Write space information from those
it can simulate writing and it issues no realistic write space information. 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 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. 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 One may distinguish pseudo-drives from MMC drives by call
burn_drive_get_drive_role(). 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 @param d The drive to inquire
@return 0= null-drive @return 0= null-drive
1= real MMC 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); int burn_drive_get_drive_role(struct burn_drive *d);

View File

@ -332,7 +332,7 @@ int burn_read_data(struct burn_drive *d, off_t byte_address,
libdax_msgs_submit(libdax_messenger, libdax_msgs_submit(libdax_messenger,
d->global_index, 0x00020142, d->global_index, 0x00020142,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, 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; return 0;
} }
if (d->drive_role == 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, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Drive is a virtual placeholder (null-drive)", 0, 0); "Drive is a virtual placeholder (null-drive)", 0, 0);
return 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) { if ((byte_address % alignment) != 0) {
sprintf(msg, sprintf(msg,

View File

@ -121,7 +121,12 @@ struct burn_format_descr {
/** Gets initialized in enumerate_common() and burn_drive_register() */ /** Gets initialized in enumerate_common() and burn_drive_register() */
struct burn_drive 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 drive_role;
int bus_no; int bus_no;

View File

@ -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)) if (o->start_byte >= 0 && (o->start_byte % 32768))
strcat(reasons, strcat(reasons,
"write start address not properly aligned to 32k, "); "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 == 0x15 ||
d->current_profile == 0x1b || d->current_profile == 0x2b ) { 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) if (o->start_byte >= 0)
strcat(reasons, "write start address not supported, "); strcat(reasons, "write start address not supported, ");
} else { } 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 */ if (d->devname[0] == 0) /* null drives should not come here */
return -1; 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) { if (fd == -1) {
libdax_msgs_submit(libdax_messenger, d->global_index, libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020005, 0x00020005,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Failed to open device (a pseudo-drive)", errno, 0); "Failed to open device (a pseudo-drive)", errno, 0);
d->cancel = 1;
return -1; return -1;
} }
if (start_byte < 0) if (start_byte < 0)
start_byte = 0; start_byte = 0;
if (lseek(fd, start_byte, SEEK_SET)==-1) { if (d->drive_role == 2)
sprintf(msg, "Cannot address start byte %.f", if (lseek(fd, start_byte, SEEK_SET)==-1) {
(double) start_byte); sprintf(msg, "Cannot address start byte %.f",
libdax_msgs_submit(libdax_messenger, d->global_index, (double) start_byte);
0x00020147, libdax_msgs_submit(libdax_messenger, d->global_index,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, 0x00020147,
msg, errno, 0); LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
close(fd); msg, errno, 0);
fd = -1; close(fd);
} d->cancel = 1;
fd = -1;
}
d->nwa = start_byte / sector_size; d->nwa = start_byte / sector_size;
return fd; 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, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"syncing cache (stdio fsync)", 0, 0); "syncing cache (stdio fsync)", 0, 0);
if (fsync(fd) != 0) { if (fsync(fd) != 0) {
if (errno == EINVAL) /* E.g. /dev/null cannot fsync */
return 1;
libdax_msgs_submit(libdax_messenger, d->global_index, libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020148, 0x00020148,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, 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; d->progress.sectors = 0;
ret = 1; ret = 1;
ex:; ex:;
if (d->stdio_fd != -1) { if (d->stdio_fd >= 0)
close (d->stdio_fd); close(d->stdio_fd);
d->stdio_fd = -1; d->stdio_fd = -1;
}
/* update media state records */ /* update media state records */
burn_drive_mark_unready(d); burn_drive_mark_unready(d);
@ -2203,7 +2213,7 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address,
return 0; return 0;
} }
if(d->drive_role != 1) if(d->drive_role == 2)
alignment = 2 * 1024; alignment = 2 * 1024;
if (d->current_profile == 0x12) /* DVD-RAM */ if (d->current_profile == 0x12) /* DVD-RAM */
alignment = 2 * 1024; alignment = 2 * 1024;
@ -2277,7 +2287,7 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address,
} }
if (err == BE_CANCELLED) { if (err == BE_CANCELLED) {
d->busy = BURN_DRIVE_IDLE; d->busy = BURN_DRIVE_IDLE;
if(fd != -1) if(fd >= 0)
close(fd); close(fd);
return (-(start * 2048 - byte_address)); 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); burn_stdio_sync_cache(fd, d, 0);
} }
if(fd != -1) if(fd >= 0)
close(fd); close(fd);
d->buffer = NULL; d->buffer = NULL;
d->busy = BURN_DRIVE_IDLE; d->busy = BURN_DRIVE_IDLE;