libisoburn/xorriso/drive_mgt.c

2248 lines
74 KiB
C
Raw Normal View History

/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2010 Thomas Schmitt, <scdbackup@gmx.net>
Provided under GPL version 2 or later.
This file contains functions which operate on drives and media.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include "xorriso.h"
#include "xorriso_private.h"
#include "lib_mgt.h"
#include "drive_mgt.h"
#include "iso_img.h"
#include "sort_cmp.h"
#include "write_run.h"
#include "read_run.h"
static const char *un0(const char *text)
{
if(text == NULL)
return("");
return(text);
}
int Xorriso_auto_driveadr(struct XorrisO *xorriso, char *adr, char *result,
int flag)
{
int ret, is_known_mmc= 0;
char *path_pt, libburn_adr[BURN_DRIVE_ADR_LEN + SfileadrL];
char *abs_pt, abs_adr[SfileadrL];
path_pt= adr;
if(strncmp(adr, "stdio:", 6) == 0)
path_pt= adr + 6;
else if(strncmp(adr, "mmc:", 4) == 0)
path_pt= adr + 4;
/* <<< replace by Xorriso_normalize_img_path() ? */;
if(path_pt[0] != '/') {
abs_pt= getcwd(abs_adr, SfileadrL - 1);
if(abs_pt == NULL) {
Xorriso_msgs_submit(xorriso, 0,
"Relative drive path given. Cannot determine working directory.",
errno, "FAILURE", 0);
return(-1);
}
ret= Sfile_add_to_path(abs_adr, path_pt, 0);
if(ret <= 0)
return(-1);
}
is_known_mmc= burn_drive_convert_fs_adr(path_pt, libburn_adr);
Xorriso_process_msg_queues(xorriso,0);
ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_whitelist, path_pt, 0);
if(ret > 0)
goto ok;
ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_blacklist, path_pt, 0);
if(ret < 0)
return(ret);
if(ret) {
strcpy(xorriso->info_text, "Drive address ");
Text_shellsafe(adr, xorriso->info_text, 1);
strcat(xorriso->info_text,
" rejected because: -drive_class 'banned' ");
Text_shellsafe(Xorriso_get_pattern(xorriso, xorriso->drive_blacklist,
ret - 1, 0),
xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
/* if in greylist and not MMC and not stdio prefix: reject */
if(is_known_mmc < 0)
return(ret);
if(adr == path_pt && !is_known_mmc) { /* no prefix, no MMC */
ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_greylist, path_pt,0);
if(ret < 0)
return(ret);
if(ret) {
strcpy(xorriso->info_text, "Drive address ");
Text_shellsafe(adr, xorriso->info_text, 1);
strcat(xorriso->info_text,
" rejected because: not MMC and -drive_class 'risky' ");
Text_shellsafe(Xorriso_get_pattern(xorriso,xorriso->drive_greylist,
ret - 1, 0),
xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
Xorriso_msgs_submit(xorriso, 0,
"If the address is a legitimate target, prepend \"stdio:\"",
0, "HINT", 0);
return(0);
}
}
ok:;
if(strncmp(adr, "mmc:", 4) == 0) {
if(Sfile_str(result, path_pt, 0) <= 0)
return(0);
} else if(adr == path_pt && is_known_mmc <= 0) {
Sfile_str(result, "stdio:", 0);
if(Sfile_str(result, adr, 1) <= 0)
return(0);
} else {
if(Sfile_str(result, adr, 0) <= 0)
return(0);
}
if(strncmp(result, "stdio:", 6)==0) {
if(xorriso->ban_stdio_write) {
strcpy(xorriso->info_text, "Drive address banned by -ban_stdio_write : ");
Text_shellsafe(result, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
}
return(1);
}
/* @param flag bit0= aquire as isoburn input drive
bit1= aquire as libburn output drive (as isoburn drive if bit0)
bit2= regard overwriteable media as blank
bit3= if the drive is a regular disk file: truncate it to
the write start address
bit5= do not print toc
bit6= do not calm down drive after aquiring it
@return <=0 failure , 1= ok
2=success, but not writeable with bit1
3=success, but not blank and not ISO with bit0
*/
int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag)
{
int ret, hret, not_writeable= 0, has_what, aquire_flag, load_lba, ext;
int lba, track, session, params_flag, adr_mode, read_ret;
uint32_t size;
struct burn_drive_info *dinfo= NULL, *out_dinfo, *in_dinfo;
struct burn_drive *drive= NULL, *out_drive, *in_drive;
enum burn_disc_status state;
IsoImage *volset = NULL;
IsoNode *root_node;
struct isoburn_read_opts *ropts= NULL;
char libburn_adr[SfileadrL], *boot_fate, *sev;
size_t value_length;
char *value= NULL;
double num;
char volid[33], adr_data[163], *adr_pt;
if((flag&3)==0) {
sprintf(xorriso->info_text,
"XORRISOBURN program error : Xorriso_aquire_drive bit0+bit1 not set");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
ret= Xorriso_give_up_drive(xorriso, (flag&3)|8);
if(ret<=0)
return(ret);
if(flag & 1)
xorriso->isofs_st_out= time(0) - 1;
ret= Xorriso_auto_driveadr(xorriso, adr, libburn_adr, 0);
if(ret <= 0)
return(ret);
if(strcmp(libburn_adr,"stdio:/dev/fd/1")==0) {
if(xorriso->dev_fd_1<0) {
sprintf(xorriso->info_text,
"-*dev \"stdio:/dev/fd/1\" was not a start argument. Cannot use it now.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
} else {
sprintf(libburn_adr, "stdio:/dev/fd/%d", xorriso->dev_fd_1);
}
}
if((flag&3)==1 && xorriso->out_drive_handle!=NULL) {
ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
"on attempt to compare new indev with outdev", 2);
if(ret<=0)
goto ex;
ret= burn_drive_equals_adr(out_drive, libburn_adr, 1);
if(ret==1) {
dinfo= out_dinfo;
xorriso->indev_is_exclusive= xorriso->outdev_is_exclusive;
}
} else if((flag&3)==2 && xorriso->in_drive_handle!=NULL) {
ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive,
"on attempt to compare new outdev with indev", 0);
if(ret<=0)
goto ex;
ret= burn_drive_equals_adr(in_drive, libburn_adr, 1);
if(ret==1) {
dinfo= in_dinfo;
xorriso->outdev_is_exclusive= xorriso->indev_is_exclusive;
}
}
if(dinfo==NULL) {
aquire_flag= 1 | ((flag&(8|4))>>1) | ((xorriso->toc_emulation_flag & 3)<<3);
if(xorriso->toc_emulation_flag & 4)
aquire_flag|= 128;
if(!(xorriso->do_aaip & 1))
aquire_flag|= 32;
if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (4 | 32)))
aquire_flag|= 64;
burn_preset_device_open(xorriso->drives_exclusive, 0, 0);
ret= isoburn_drive_aquire(&dinfo, libburn_adr, aquire_flag);
burn_preset_device_open(1, 0, 0);
Xorriso_process_msg_queues(xorriso,0);
if(ret<=0) {
sprintf(xorriso->info_text,"Cannot aquire drive '%s'", adr);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
if(flag&1)
if(xorriso->image_start_mode&(1<<31)) /* used up setting */
xorriso->image_start_mode= 0; /* no need to perform auto setting */
if(flag & 1)
xorriso->indev_is_exclusive= xorriso->drives_exclusive;
if(flag & 2)
xorriso->outdev_is_exclusive= xorriso->drives_exclusive;
}
drive= dinfo[0].drive;
if(flag&1) {
if(xorriso->image_start_mode&(1<<31)) /* used up setting */
xorriso->image_start_mode&= ~0xffff; /* perform auto setting */
if((xorriso->image_start_mode&(1<<30))) { /* if enabled at all */
adr_pt= xorriso->image_start_value;
adr_mode= xorriso->image_start_mode & 0xffff;
if(adr_mode == 4 && strlen(adr_pt) <= 80) {
/* Convert volid search expression into lba */
params_flag= 0;
ret= Xorriso__bourne_to_reg(xorriso->image_start_value, adr_data, 0);
if(ret == 1)
params_flag|= 4;
ret= isoburn_get_mount_params(drive, 4, adr_data, &lba, &track,
&session, volid, params_flag);
Xorriso_process_msg_queues(xorriso,0);
if(ret <= 0)
goto ex;
if(session <= 0 || track <= 0 || ret == 2) {
Xorriso_msgs_submit(xorriso, 0,
"-load : Given address does not point to an ISO 9660 session",
0, "FAILURE", 0);
ret= 0; goto ex;
}
sprintf(volid, "%d", lba);
adr_pt= volid;
adr_mode= 3;
}
ret= isoburn_set_msc1(drive, adr_mode, adr_pt,
!!(xorriso->image_start_mode & (1<<16)));
if(ret<=0)
goto ex;
if(xorriso->image_start_mode&(1<<31))
xorriso->image_start_mode= 0; /* disable msc1 setting completely */
else
xorriso->image_start_mode|= (1<<31); /* mark as used up */
}
}
state= isoburn_disc_get_status(drive);
Xorriso_process_msg_queues(xorriso,0);
if(flag&1) {
volset= isoburn_get_attached_image(drive);
if(volset != NULL) { /* The image object is already created */
iso_image_unref(volset);
}
}
if(flag&2) {
xorriso->out_drive_handle= dinfo;
if(Sfile_str(xorriso->outdev, adr, 0)<=0)
{ret= -1; goto ex;}
if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE) {
sprintf(xorriso->info_text, "Disc status unsuitable for writing");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
not_writeable= 1;
}
}
if(flag&1) {
xorriso->in_drive_handle= dinfo;
if(Sfile_str(xorriso->indev, adr, 0)<=0)
{ret= -1; goto ex;}
} else if(flag&2) {
if(xorriso->in_volset_handle==NULL) {
/* No volume loaded: create empty one */
ret= Xorriso_create_empty_iso(xorriso, 0);
if(ret<=0)
goto ex;
} else {
iso_image_ref((IsoImage *) xorriso->in_volset_handle);
ret= isoburn_attach_image(drive, (IsoImage *) xorriso->in_volset_handle);
if(ret<=0) {
sprintf(xorriso->info_text,
"Failed to attach ISO image object to outdev");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
{ret= -1; goto ex;}
}
}
if(!(flag&32))
Xorriso_toc(xorriso, 1 | 2 | 8);
{ret= 1+not_writeable; goto ex;}
}
if(xorriso->in_volset_handle!=NULL)
iso_image_unref((IsoImage *) xorriso->in_volset_handle);
xorriso->in_volset_handle= NULL;
Sectorbitmap_destroy(&(xorriso->in_sector_map), 0);
Xorriso_destroy_hln_array(xorriso, 0);
Xorriso_destroy_di_array(xorriso, 0);
xorriso->boot_count= 0;
/* check for invalid state */
if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE &&
state != BURN_DISC_FULL) {
sprintf(xorriso->info_text,
"Disc status not blank and unsuitable for reading");
sev= "FAILURE";
if(xorriso->img_read_error_mode==2)
sev= "FATAL";
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0);
Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2));
ret= 3; goto ex;
}
/* fill read opts */
ret= isoburn_ropt_new(&ropts, 0);
if(ret<=0)
goto ex;
ext= isoburn_ropt_noiso1999;
if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (1 | 4 | 32))
&& !(xorriso->do_md5 & 1))
ext|= isoburn_ropt_noaaip;
if(!(xorriso->do_aaip & 1))
ext|= isoburn_ropt_noacl;
if(!(xorriso->do_aaip & 4))
ext|= isoburn_ropt_noea;
if(xorriso->ino_behavior & 1)
ext|= isoburn_ropt_noino;
#ifdef isoburn_ropt_nomd5
if(!(xorriso->do_md5 & 1))
ext|= isoburn_ropt_nomd5;
#endif
isoburn_ropt_set_extensions(ropts, ext);
isoburn_ropt_set_default_perms(ropts, (uid_t) 0, (gid_t) 0, (mode_t) 0555);
isoburn_ropt_set_input_charset(ropts, xorriso->in_charset);
isoburn_ropt_set_auto_incharset(ropts, !!(xorriso->do_aaip & 512));
Xorriso_set_image_severities(xorriso, 1); /* No DEBUG messages */
Xorriso_pacifier_reset(xorriso, 0);
isoburn_set_read_pacifier(drive, Xorriso__read_pacifier, (void *) xorriso);
/* <<< Trying to work around too much tolerance on bad image trees.
Better would be a chance to instruct libisofs what to do in
case of image read errors. There is a risk to mistake other SORRYs.
*/
if(xorriso->img_read_error_mode>0)
iso_set_abort_severity("SORRY");
if(state != BURN_DISC_BLANK) {
ret= isoburn_disc_get_msc1(drive, &load_lba);
if(ret > 0) {
sprintf(xorriso->info_text,
"Loading ISO image tree from LBA %d", load_lba);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
ret= Xorriso_assert_volid(xorriso, load_lba, 0);
if(ret <= 0)
goto ex;
}
read_ret= ret= isoburn_read_image(drive, ropts, &volset);
/* <<< Resetting to normal thresholds */
if(xorriso->img_read_error_mode>0)
Xorriso_set_abort_severity(xorriso, 0);
if(ret<=0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_set_image_severities(xorriso, 0);
Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2));
sprintf(xorriso->info_text,"Cannot read ISO image tree");
sev= "FAILURE";
if(xorriso->img_read_error_mode==2)
sev= "FATAL";
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0);
if(read_ret == ISO_SB_TREE_CORRUPTED && (xorriso->do_md5 & 1)) {
Xorriso_msgs_submit(xorriso, 0,
"You might get a questionable ISO image tree by option -md5 'off'.",
0, "HINT", 0);
} else if(xorriso->img_read_error_mode!=0) {
Xorriso_msgs_submit(xorriso, 0, "You might get a partial or altered ISO image tree by option -error_behavior 'image_loading' 'best_effort' if -abort_on is set to be tolerant enough.",
0, "HINT", 0);
}
ret= 3; goto ex;
}
Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0,
"", 1); /* report end count */
xorriso->in_volset_handle= (void *) volset;
xorriso->in_sector_map= NULL;
Xorriso_set_image_severities(xorriso, 0);
Xorriso_update_volid(xorriso, 0);
strncpy(xorriso->application_id,
un0(iso_image_get_application_id(volset)), 128);
xorriso->application_id[128]= 0;
strncpy(xorriso->publisher, un0(iso_image_get_publisher_id(volset)), 128);
xorriso->publisher[128]= 0;
strncpy(xorriso->system_id, un0(iso_image_get_system_id(volset)), 32);
xorriso->system_id[32]= 0;
strncpy(xorriso->volset_id, un0(iso_image_get_volset_id(volset)), 128);
xorriso->volset_id[128]= 0;
/* <<< can be removed as soon as libisofs-0.6.24 is mandatory
*/
if(strcmp(un0(iso_image_get_copyright_file_id(volset)), "_") == 0 &&
strcmp(un0(iso_image_get_abstract_file_id(volset)), "_") == 0 &&
strcmp(un0(iso_image_get_biblio_file_id(volset)), "_") == 0) {
/* This is bug output from libisofs <= 0.6.23 . The texts mean file names
and should have been empty to indicate that there are no such files.
It is obvious that not all three roles can be fulfilled by one file "_"
so that one cannot spoil anything by assuming them empty now.
Modern versions of libisofs are supposed to do this themselves.
*/
iso_image_set_copyright_file_id(volset, "");
iso_image_set_abstract_file_id(volset, "");
iso_image_set_biblio_file_id(volset, "");
}
if(xorriso->out_drive_handle != NULL &&
xorriso->out_drive_handle != xorriso->in_drive_handle) {
ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
"on attempt to attach ISO image volset to outdev", 2);
if(ret<=0)
goto ex;
iso_image_ref((IsoImage *) xorriso->in_volset_handle);
isoburn_attach_image(out_drive, xorriso->in_volset_handle);
}
Xorriso_process_msg_queues(xorriso,0);
isoburn_ropt_get_size_what(ropts, &size, &has_what);
if(has_what & isoburn_ropt_has_el_torito) {
if(xorriso->boot_image_bin_path[0])
boot_fate= "replaced by new boot image";
else if(xorriso->patch_isolinux_image & 1)
boot_fate= "patched at boot info table";
else if(xorriso->keep_boot_image)
boot_fate= "kept unchanged";
else
boot_fate= "discarded";
sprintf(xorriso->info_text,
"Detected El-Torito boot information which currently is set to be %s",
boot_fate);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
Xorriso_record_boot_info(xorriso, 0);
}
if(flag & 1) {
/* Look for isofs.st and put it into xorriso->isofs_st_in */;
root_node= (IsoNode *) iso_image_get_root(volset);
ret= iso_node_lookup_attr(root_node, "isofs.st", &value_length, &value, 0);
if(ret > 0) {
if(value_length > 0) {
sscanf(value, "%lf", &num);
if(num > 0)
xorriso->isofs_st_in= num;
}
free(value);
}
}
if(!(flag&32)) {
Xorriso_toc(xorriso, 1 | 8);
if(xorriso->loaded_volid[0]!=0) {
sprintf(xorriso->info_text,"Volume id : '%s'\n",
xorriso->loaded_volid);
Xorriso_info(xorriso, 0);
if(strcmp(xorriso->loaded_volid, xorriso->volid) != 0 &&
!xorriso->volid_default) {
sprintf(xorriso->info_text, "New volume id: '%s'\n", xorriso->volid);
Xorriso_info(xorriso, 0);
}
}
}
ret= 1+not_writeable;
ex:
Xorriso_process_msg_queues(xorriso,0);
if(ret<=0) {
hret= Xorriso_give_up_drive(xorriso, (flag&3)|((flag&32)>>2));
if(hret<ret)
ret= hret;
} else {
if(drive != NULL && (xorriso->do_calm_drive & 1) && !(flag & 64))
burn_drive_snooze(drive, 0); /* No need to make noise from start */
}
if(ropts!=NULL)
isoburn_ropt_destroy(&ropts, 0);
return(ret);
}
/* @param flag bit0=input drive
bit1=output drive
bit2=eject
bit3=no info message or toc
*/
int Xorriso_give_up_drive(struct XorrisO *xorriso, int flag)
{
int in_is_out_too, ret, do_eject;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
char sfe[5*SfileadrL];
in_is_out_too= (xorriso->in_drive_handle == xorriso->out_drive_handle);
if((flag&4) && in_is_out_too && (flag&(1|2))) {
if((flag&3)!=3) {
sprintf(xorriso->info_text,"Giving up for -eject whole -dev %s",
Text_shellsafe(xorriso->indev, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
flag|= 3; /* give up in/out drive to eject it */
}
if((flag&1) && xorriso->in_drive_handle != NULL) {
Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to give up drive", 0);
if(!in_is_out_too) {
do_eject= !!(flag&4);
if((flag & 4) && !xorriso->indev_is_exclusive) {
sprintf(xorriso->info_text,
"Will not eject media in non-exclusively aquired input drive.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
do_eject= 0;
}
if(drive!=NULL)
isoburn_drive_release(drive, do_eject);
if(dinfo!=NULL)
burn_drive_info_free(dinfo);
}
xorriso->in_drive_handle= NULL;
xorriso->indev[0]= 0;
if(xorriso->in_volset_handle!=NULL)
iso_image_unref((IsoImage *) xorriso->in_volset_handle);
xorriso->in_volset_handle= NULL;
Sectorbitmap_destroy(&(xorriso->in_sector_map), 0);
Xorriso_destroy_di_array(xorriso, 0);
Xorriso_destroy_hln_array(xorriso, 0);
xorriso->loaded_volid[0]= 0;
xorriso->isofs_st_out= time(0) - 1;
xorriso->isofs_st_in= 0;
xorriso->volset_change_pending= 0;
xorriso->no_volset_present= 0;
xorriso->loaded_boot_bin_lba= 0;
xorriso->loaded_boot_cat_path[0]= 0;
xorriso->boot_count= 0;
in_is_out_too= 0;
}
if((flag&2) && xorriso->out_drive_handle!=NULL) {
do_eject= !!(flag&4);
if((flag & 4) && !xorriso->outdev_is_exclusive) {
sprintf(xorriso->info_text,
"Will not eject media in non-exclusively aquired drive.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
do_eject= 0;
}
Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to give up drive", 2);
if(!in_is_out_too) {
if(drive!=NULL)
isoburn_drive_release(drive, do_eject);
if(dinfo!=NULL)
burn_drive_info_free(dinfo);
}
xorriso->out_drive_handle= NULL;
xorriso->outdev[0]= 0;
} else if((flag&1) && xorriso->out_drive_handle!=NULL) {
ret= Xorriso_create_empty_iso(xorriso, 0);
if(ret<=0)
return(ret);
if(!(flag&8)) {
sprintf(xorriso->info_text,
"Only the output drive remains. Created empty ISO image.\n");
Xorriso_info(xorriso, 0);
Xorriso_toc(xorriso, 1 | 2 | 8);
}
}
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_may_burn(struct XorrisO *xorriso, int flag)
{
if(xorriso->outdev_is_exclusive)
return(1);
sprintf(xorriso->info_text, "The output drive was not aquired exclusively.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
sprintf(xorriso->info_text, "A possible remedy is: -osirrox 'o_excl_on'");
if(xorriso->outdev[0]) {
strcat(xorriso->info_text," -outdev ");
Text_shellsafe(xorriso->outdev, xorriso->info_text, 1);
}
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
return(0);
}
/* @param flag bit2=do not try to read ISO heads
*/
int Xorriso_toc_to_string(struct XorrisO *xorriso, char **toc_text, int flag)
{
int ret, stack_handle, toc_ret, l;
struct Xorriso_lsT *results= NULL, *infos= NULL, *lpt;
*toc_text= NULL;
ret= Xorriso_push_outlists(xorriso, &stack_handle, 1);
if(ret <= 0)
goto ex;
toc_ret= Xorriso_toc(xorriso, flag & 4);
ret= Xorriso_pull_outlists(xorriso, stack_handle, &results, &infos, 0);
if(ret <= 0)
goto ex;
if(toc_ret <= 0)
{ret= toc_ret; goto ex;}
l= 0;
for(lpt= results; lpt != NULL; lpt= Xorriso_lst_get_next(lpt, 0))
l+= strlen(Xorriso_lst_get_text(lpt, 0));
*toc_text= calloc(l + 1, 1);
l= 0;
for(lpt= results; lpt != NULL; lpt= Xorriso_lst_get_next(lpt, 0)) {
strcpy((*toc_text) + l, Xorriso_lst_get_text(lpt, 0));
l+= strlen(Xorriso_lst_get_text(lpt, 0));
}
ex:;
Xorriso_lst_destroy_all(&results, 0);
Xorriso_lst_destroy_all(&infos, 0);
return(ret);
}
/* @param flag bit0+1= what to aquire after giving up outdev
0=none, 1=indev, 2=outdev, 3=both
*/
int Xorriso_reaquire_outdev(struct XorrisO *xorriso, int flag)
{
int ret, aq_flag;
char drive_name[SfileadrL], sfe[5*SfileadrL];
aq_flag= flag&3;
strcpy(drive_name, xorriso->outdev);
Xorriso_give_up_drive(xorriso, aq_flag);
if(aq_flag==0) {
sprintf(xorriso->info_text,"Gave up -outdev %s",
Text_shellsafe(xorriso->outdev, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(1);
}
sprintf(xorriso->info_text,"Re-aquiring -outdev %s",
Text_shellsafe(drive_name, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= Xorriso_aquire_drive(xorriso, drive_name, aq_flag);
if(ret<=0) {
sprintf(xorriso->info_text,"Could not re-aquire -outdev %s",
Text_shellsafe(xorriso->outdev, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(ret);
}
return(1);
}
/* @param flag
bit3=report to info channel (else to result channel)
*/
int Xorriso_toc_line(struct XorrisO *xorriso, int flag)
{
if(!(flag & 8)) {
Xorriso_result(xorriso,0);
return(1);
}
strcpy(xorriso->info_text, xorriso->result_line);
Xorriso_info(xorriso, 0);
return(1);
}
/* @param flag
bit1=report about output drive
bit3=report to info channel (else to result channel)
bit4=do no report failure if no drive aquired
*/
int Xorriso_media_product(struct XorrisO *xorriso, int flag)
{
int ret, profile_no;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
char *product_id= NULL, *media_code1= NULL, *media_code2= NULL;
char *book_type= NULL, *manuf= NULL, profile_name[80], *respt;
respt= xorriso->result_line;
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to print media product info",
flag & (2 | 16));
if(ret <= 0)
return(ret);
ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2,
&book_type, 0);
if(ret > 0) {
ret= burn_disc_get_profile(drive, &profile_no, profile_name);
if(ret <= 0)
return(ret);
sprintf(respt, "Media product: %s , ", product_id);
manuf= burn_guess_manufacturer(profile_no, media_code1, media_code2, 0);
if(manuf != NULL) {
if(strncmp(manuf, "Unknown ", 8) == 0)
sprintf(respt + strlen(respt), "(not found in manufacturer list)\n");
else
sprintf(respt + strlen(respt), "%s\n", manuf);
} else
sprintf(respt + strlen(respt), "(error during manufacturer lookup)\n");
free(product_id);
free(media_code1);
free(media_code2);
if(book_type != NULL)
free(book_type);
if(manuf != NULL)
free(manuf);
Xorriso_toc_line(xorriso, flag & 8);
}
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
/* @param flag bit0=short report form
bit1=report about output drive
bit2=do not try to read ISO heads
bit3=report to info channel (else to result channel)
bit4=do no report failure if no drive aquired
bit5=only report "Drive current" and "Drive type"
bit6=report "Media product" with bit0
bit7=only report "Drive current"
*/
int Xorriso_toc(struct XorrisO *xorriso, int flag)
{
int num_sessions= 0, num_tracks= 0, lba= 0, nwa= -1, pmin, psec, pframe, ret;
int track_count= 0, session_no, track_no, profile_no= -1, track_size;
int last_track_start= 0, last_track_size= -1, num_data= 0, is_data= 0;
int is_inout_drive= 0, drive_role, status, num_formats, emul_lba;
int num_payload= 0, num_wasted= 0, num_nondata= 0, not_reconizable= 0;
char profile_name[80],*respt,*devadr, *typetext= "";
struct burn_toc_entry toc_entry;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
enum burn_disc_status s;
char mem_text[80];
off_t start_byte= 0, num_free= 0, size;
unsigned dummy;
struct isoburn_toc_disc *disc= NULL;
struct isoburn_toc_session **sessions;
struct isoburn_toc_track **tracks;
int image_blocks= 0;
char volume_id[33];
struct burn_toc_entry next_toc_entry;
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to print Table Of Content",
flag & (2 | 16));
if(ret<=0)
{ret= 0; goto ex;}
respt= xorriso->result_line;
if(strcmp(xorriso->indev, xorriso->outdev)==0)
is_inout_drive= 1;
if(flag&2)
devadr= xorriso->outdev;
else
devadr= xorriso->indev;
sprintf(respt, "Drive current: %s '%s'\n",
(is_inout_drive ? "-dev" : (flag&2 ? "-outdev" : "-indev")),
devadr);
Xorriso_toc_line(xorriso, flag & 8);
if(flag & 128)
{ret= 1; goto ex;}
sprintf(respt, "Drive type : vendor '%s' product '%s' revision '%s'\n",
dinfo[0].vendor, dinfo[0].product, dinfo[0].revision);
if((flag & 32) | !(flag & 1))
Xorriso_toc_line(xorriso, flag & 8);
if(flag & 32)
{ret= 1; goto ex;}
ret= burn_disc_get_profile(drive, &profile_no, profile_name);
s= isoburn_disc_get_status(drive);
if(profile_no == 0x0002 && s == BURN_DISC_EMPTY)
profile_no= 0;
sprintf(respt, "Media current: ");
if (profile_no > 0 && ret > 0) {
if (profile_name[0])
sprintf(respt+strlen(respt), "%s", profile_name);
else
sprintf(respt+strlen(respt), "%4.4Xh", profile_no);
drive_role= burn_drive_get_drive_role(drive);
if(drive_role==2)
sprintf(respt+strlen(respt), ", overwriteable");
else if(drive_role==0 || drive_role==3)
sprintf(respt+strlen(respt), ", sequential");
strcat(respt, "\n");
} else {
sprintf(respt+strlen(respt), "is not recognizable\n");
not_reconizable= 1;
}
Xorriso_toc_line(xorriso, flag & 8);
if((flag & 64) || !(flag & 1)) {
Xorriso_media_product(xorriso, flag & (2 | 8 | 16));
if(xorriso->request_to_abort)
{ret= 1; goto ex;}
}
sprintf(respt, "Media status : ");
if (s == BURN_DISC_FULL) {
if(not_reconizable)
sprintf(respt+strlen(respt), "is not recognizable\n");
else
sprintf(respt+strlen(respt), "is written , is closed\n");
} else if (s == BURN_DISC_APPENDABLE) {
sprintf(respt+strlen(respt), "is written , is appendable\n");
} else if (s == BURN_DISC_BLANK) {
sprintf(respt+strlen(respt), "is blank\n");
} else if (s == BURN_DISC_EMPTY)
sprintf(respt+strlen(respt), "is not present\n");
else
sprintf(respt+strlen(respt), "is not recognizable\n");
Xorriso_toc_line(xorriso, flag & 8);
if(s == BURN_DISC_BLANK) {
sprintf(respt, "Media summary: 0 sessions, 0 data blocks, 0 data");
num_free= isoburn_disc_available_space(drive, NULL);
Sfile_scale((double) num_free, mem_text,5,1e4,1);
sprintf(respt+strlen(respt), ", %s free\n", mem_text);
Xorriso_toc_line(xorriso, flag & 8);
}
if(s != BURN_DISC_FULL && s != BURN_DISC_APPENDABLE)
{ret= 1; goto ex;}
if(xorriso->request_to_abort)
{ret= 1; goto ex;}
if(!(flag & 2))
Xorriso_show_boot_info(xorriso, 1 | (flag & 8) | ((flag & 1) << 1));
disc= isoburn_toc_drive_get_disc(drive);
if(flag & 4)
sprintf(respt, "TOC layout : %3s , %9s , %10s\n",
"Idx", "sbsector", "Size");
else
sprintf(respt, "TOC layout : %3s , %9s , %10s , %s\n",
"Idx", "sbsector", "Size", "Volume Id");
if(!(flag&1))
Xorriso_toc_line(xorriso, flag & 8);
if (disc==NULL) {
Xorriso_process_msg_queues(xorriso,0);
ret= isoburn_get_min_start_byte(drive, &start_byte, 0);
nwa= start_byte / 2048;
if(ret<=0) {
Xorriso_process_msg_queues(xorriso,0);
if(flag&1)
{ret= 0; goto ex;}
sprintf(xorriso->info_text, "Cannot obtain Table Of Content");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
{ret= 0; goto ex;}
}
/* fabricate TOC */
typetext= "Other session";
if(flag & 4) {
ret= 0;
typetext= "Session ";
} else
ret= isoburn_read_iso_head(drive, 0, &image_blocks, volume_id, 1);
if(ret>0) {
sprintf(respt, "ISO session : %3d , %9d , %9ds , %s\n",
1, 0, image_blocks, volume_id);
nwa= image_blocks;
} else {
nwa= 0;
ret= burn_disc_get_formats(drive, &status, &size, &dummy,
&num_formats);
if(ret>0 && status==BURN_FORMAT_IS_FORMATTED)
nwa= size/2048;
sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
typetext, 1, 0, nwa);
}
if(!(flag&1))
Xorriso_toc_line(xorriso, flag & 8);
last_track_start= lba;
num_payload= num_data= last_track_size= nwa;
num_sessions= 1;
} else {
sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions);
for (session_no= 0; session_no<num_sessions && !(xorriso->request_to_abort);
session_no++) {
tracks= isoburn_toc_session_get_tracks(sessions[session_no], &num_tracks);
if (tracks==NULL)
continue;
for(track_no= 0; track_no<num_tracks && !(xorriso->request_to_abort);
track_no++) {
track_count++;
is_data= 0;
isoburn_toc_track_get_entry(tracks[track_no], &toc_entry);
if (toc_entry.extensions_valid & 1) {
/* DVD extension valid */
lba= toc_entry.start_lba;
track_size= toc_entry.track_blocks;
} else {
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
toc_entry.pframe);
if(track_no==num_tracks-1) {
isoburn_toc_session_get_leadout_entry(sessions[session_no],
&next_toc_entry);
} else {
isoburn_toc_track_get_entry(tracks[track_no+1], &next_toc_entry);
}
track_size= burn_msf_to_lba(next_toc_entry.pmin, next_toc_entry.psec,
next_toc_entry.pframe) - lba;
}
if(flag&(1|4))
ret= 0;
else {
ret= isoburn_toc_track_get_emul(tracks[track_no], &emul_lba,
&image_blocks, volume_id, 0);
if(ret <= 0)
ret= isoburn_read_iso_head(drive, lba, &image_blocks, volume_id, 1);
if(image_blocks > track_size) {
sprintf(xorriso->info_text,
"Session %d bears ISO image size %ds larger than track size %ds",
session_no + 1, image_blocks, track_size);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING",
0);
image_blocks= track_size;
}
}
if(ret>0 && track_no==0) {
sprintf(respt, "ISO session : %3d , %9d , %9ds , %s\n",
session_no+1, lba, image_blocks , volume_id);
} else if(ret>0) {
sprintf(respt, "ISO track : %3d , %9d , %9ds , %s\n",
track_count, lba, image_blocks , volume_id);
} else if(track_no==0) {
typetext= "Other session";
if(flag & 4)
typetext= "Session ";
sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
typetext, session_no+1, lba, track_size);
} else {
typetext= "Other track ";
if(flag & 4)
typetext= "Track ";
sprintf(respt, "%13s: %3d , %9d , %9ds , \n",
typetext, track_count, lba, track_size);
}
if(!(flag&1))
Xorriso_toc_line(xorriso, flag & 8);
if(track_no>0)
num_payload+= lba - last_track_start;
last_track_start= lba;
if((toc_entry.control&7)>=4) /* data track */
is_data= 1;
}
isoburn_toc_session_get_leadout_entry(sessions[session_no], &toc_entry);
if (toc_entry.extensions_valid & 1) {
lba= toc_entry.start_lba;
burn_lba_to_msf(lba, &pmin, &psec, &pframe);
} else {
lba= burn_msf_to_lba(pmin, psec, pframe);
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe);
}
last_track_size= lba - last_track_start;
num_payload+= last_track_size;
if(is_data)
num_data+= last_track_size;
}
}
if(xorriso->request_to_abort)
{ret= 1; goto ex;}
num_wasted= lba - num_payload;
num_nondata= lba - num_data;
Sfile_scale(((double) num_data) * 2048.0, mem_text,5,1e4,1);
sprintf(respt, "Media summary: %d session%s, %d data blocks, %s data",
num_sessions, (num_sessions==1 ? "" : "s"), num_data, mem_text);
num_free= isoburn_disc_available_space(drive, NULL);
Sfile_scale((double) num_free, mem_text,5,1e4,1);
sprintf(respt+strlen(respt), ", %s free", mem_text);
sprintf(respt+strlen(respt), "\n");
Xorriso_toc_line(xorriso, flag & 8);
if (s==BURN_DISC_APPENDABLE && nwa!=0) {
ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
if(ret>0) {
sprintf(respt, "Media nwa : %ds\n", nwa);
if(!(flag&1))
Xorriso_toc_line(xorriso, flag & 8);
}
}
if (disc!=NULL)
isoburn_toc_disc_free(disc);
Xorriso_process_msg_queues(xorriso,0);
ret= 1;
ex:;
return(ret);
}
int Xorriso_show_devices(struct XorrisO *xorriso, int flag)
{
char adr[BURN_DRIVE_ADR_LEN];
int i, j, max_dev_len= 1, pad;
struct burn_drive_info *drive_list= NULL;
unsigned int drive_count;
char *respt, perms[8];
struct stat stbuf;
sprintf(xorriso->info_text, "Beginning to scan for devices ...\n");
Xorriso_info(xorris