libisoburn/libisoburn/burn_wrap.c

723 lines
19 KiB
C

/*
cc -g -c \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
burn_wrap.c
*/
/* libburn wrappers for libisoburn
Copyright 2007 Thomas Schmitt, <scdbackup@gmx.net>
*/
/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo
#define Hardcoded_cd_rW 1
#define Hardcoded_cd_rw_c1 12999
#define Hardcoded_cd_rw_nwA 152660
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef Xorriso_standalonE
#include <libburn/libburn.h>
#include <libisofs/libisofs.h>
#else /* ! Xorriso_standalonE */
#include "../libisofs/libisofs.h"
#include "../libburn/libburn.h"
#endif /* Xorriso_standalonE */
#include "libisoburn.h"
#include "isoburn.h"
/* The global list of isoburn objects. Usually there is only one. */
extern struct isoburn *isoburn_list_start; /* in isoburn.c */
int isoburn_initialize(char msg[1024], int flag)
{
int major, minor, micro, bad_match= 0;
/* First two ugly compile time checks for header version compatibility.
If everthing matches, then they produce no C code. In case of mismatch,
intentionally faulty C code will be inserted.
*/
#ifdef iso_lib_header_version_major
/* The minimum requirement of libisoburn towards the libisofs header
at compile time is defined in libisoburn/libisoburn.h :
isoburn_libisofs_req_major
isoburn_libisofs_req_minor
isoburn_libisofs_req_micro
It gets compared against the version macros in libisofs/libisofs.h :
iso_lib_header_version_major
iso_lib_header_version_minor
iso_lib_header_version_micro
If the header is too old then the following code shall cause failure of
cdrskin compilation rather than to allow production of a program with
unpredictable bugs or memory corruption.
The compiler messages supposed to appear in this case are:
error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function)
error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function)
*/
/* The indendation is an advise of man gcc to help old compilers ignoring */
#if isoburn_libisofs_req_major > iso_lib_header_version_major
#define Isoburn_libisofs_dot_h_too_olD 1
#endif
#if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor
#define Isoburn_libisofs_dot_h_too_olD 1
#endif
#if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro
#define Isoburn_libisofs_dot_h_too_olD 1
#endif
#ifdef Isoburn_libisofs_dot_h_too_olD
LIBISOFS_MISCONFIGURATION = 0;
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
LIBISOFS_MISCONFIGURATION_ = 0;
#endif
#endif /* iso_lib_header_version_major */
/* The minimum requirement of libisoburn towards the libburn header
at compile time is defined in libisoburn/libisoburn.h :
isoburn_libburn_req_major
isoburn_libburn_req_minor
isoburn_libburn_req_micro
It gets compared against the version macros in libburn/libburn.h :
burn_header_version_major
burn_header_version_minor
burn_header_version_micro
If the header is too old then the following code shall cause failure of
cdrskin compilation rather than to allow production of a program with
unpredictable bugs or memory corruption.
The compiler messages supposed to appear in this case are:
error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
*/
/* The indendation is an advise of man gcc to help old compilers ignoring */
#if isoburn_libburn_req_major > burn_header_version_major
#define Isoburn_libburn_dot_h_too_olD 1
#endif
#if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor
#define Isoburn_libburn_dot_h_too_olD 1
#endif
#if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro
#define Isoburn_libburn_dot_h_too_olD 1
#endif
#ifdef Isoburn_libburn_dot_h_too_olD
LIBBURN_MISCONFIGURATION = 0;
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
LIBBURN_MISCONFIGURATION_ = 0;
#endif
/* End of ugly compile time tests (scroll up for explanation) */
msg[0]= 0;
if(iso_init()<0) {
sprintf(msg+strlen(msg), "Cannot initialize libisofs\n");
return(0);
}
iso_lib_version(&major, &minor, &micro);
sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro);
#ifdef iso_lib_header_version_major
if(iso_lib_is_compatible(iso_lib_header_version_major,
iso_lib_header_version_minor,
iso_lib_header_version_micro)) {
sprintf(msg+strlen(msg), "ok, ");
} else {
sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
iso_lib_header_version_major, iso_lib_header_version_minor,
iso_lib_header_version_micro);
bad_match= 1;
}
#else
if(iso_lib_is_compatible(isoburn_libisofs_req_major,
isoburn_libisofs_req_minor,
isoburn_libisofs_req_micro)) {
sprintf(msg+strlen(msg), "suspicious, ");
} else {
sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
isoburn_libisofs_req_major, isoburn_libisofs_req_minor,
isoburn_libisofs_req_micro);
bad_match= 1;
}
#endif /* ! iso_lib_header_version_major */
if(!burn_initialize()) {
sprintf(msg+strlen(msg), "Cannot initialize libburn\n");
return(0);
}
burn_version(&major, &minor, &micro);
sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro);
if(major > burn_header_version_major
|| (major == burn_header_version_major
&& (minor > burn_header_version_minor
|| (minor == burn_header_version_minor
&& micro >= burn_header_version_micro)))) {
sprintf(msg+strlen(msg), "ok, ");
} else {
sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n",
burn_header_version_major, burn_header_version_minor,
burn_header_version_micro);
bad_match= 1;
}
isoburn_version(&major, &minor, &micro);
sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro);
if(bad_match)
return(0);
isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */
return(1);
}
/** Examine the media and sets appropriate emulation if needed.
*/
static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
int flag)
{
int ret, lba, nwa;
struct burn_multi_caps *caps= NULL;
ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0);
if(ret<0) /* == 0 is read-only media, but it is too early to reject it here */
goto ex;
ret= isoburn_new(o, 0);
if(ret<=0)
goto ex;
(*o)->drive= d;
#ifdef Hardcoded_cd_rW
/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
caps->start_adr= 0;
(*o)->fabricated_disc_status= BURN_DISC_APPENDABLE;
#endif
if(caps->start_adr) { /* set emulation to overwriteable */
(*o)->emulation_mode= 1;
ret= isoburn_start_emulation(*o, 0);
if(ret<=0) {
(*o)->emulation_mode= -1;
goto ex;
}
} else {
/* >>> recognize unsuitable media (but allow read-only media) */;
#ifdef Hardcoded_cd_rW
(*o)->nwa= Hardcoded_cd_rw_nwA;
#else
ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
if(ret>0)
(*o)->nwa= nwa;
#endif
}
ret= 1;
ex:
if(caps!=NULL)
burn_disc_free_multi_caps(&caps);
return(ret);
}
int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
char *adr, int load)
{
int ret, conv_ret, drive_grabbed= 0;
char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
struct isoburn *o= NULL;
char msg[BURN_MSGS_MESSAGE_LEN+4096];
conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr);
if(conv_ret<=0) {
sprintf(msg, "Unsuitable drive address: '%s'\n",adr);
msg[BURN_MSGS_MESSAGE_LEN-1]= 0;
burn_msgs_submit(0, msg, 0, "SORRY", NULL);
ret= 0; goto ex;
}
ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, load);
if(ret<=0)
goto ex;
drive_grabbed= 1;
ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, 0);
if(ret<=0)
goto ex;
ret= 1;
ex:
if(ret<=0) {
if(drive_grabbed)
burn_drive_release((*drive_infos)[0].drive, 0);
isoburn_destroy(&o, 0);
}
return(ret);
}
int isoburn_drive_grab(struct burn_drive *drive, int load)
{
int ret;
struct isoburn *o= NULL;
ret= burn_drive_grab(drive, load);
if(ret<=0)
goto ex;
ret= isoburn_welcome_media(&o, drive, 0);
if(ret<=0)
goto ex;
ret= 1;
ex:
if(ret<=0)
isoburn_destroy(&o,0);
return(ret);
}
/** Retrieve media emulation and eventual isoburn emulator of drive.
@return -1 unsuitable media, 0 generic media, 1 emulated media.
*/
int isoburn_find_emulator(struct isoburn **pt,
struct burn_drive *drive, int flag)
{
int ret;
ret= isoburn_find_by_drive(pt, drive, 0);
if(ret<=0)
return(0);
if((*pt)->emulation_mode==-1)
return(-1);
if((*pt)->emulation_mode==0)
return(0);
return(1);
}
enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, drive, 0);
if(ret<0)
return(BURN_DISC_UNSUITABLE);
if(o!=NULL)
if(o->fabricated_disc_status!=BURN_DISC_UNREADY)
return(o->fabricated_disc_status);
if(ret==0)
return(burn_disc_get_status(drive));
/* emulated status */
if(o->emulation_mode==-1)
return(BURN_DISC_UNSUITABLE);
if(o->nwa>0)
return(BURN_DISC_APPENDABLE);
return(BURN_DISC_BLANK);
}
int isoburn_disc_erasable(struct burn_drive *d)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, d, 0);
if(ret>0)
if(o->emulation_mode==1)
return(1);
return burn_disc_erasable(d);
}
void isoburn_disc_erase(struct burn_drive *drive, int fast)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, drive, 0);
if(ret>0) {
if(o->emulation_mode==-1) {
/* To cause a negative reply with burn_drive_wrote_well() */
burn_drive_cancel(drive);
return;
}
if(o->emulation_mode>0) {
ret= isoburn_invalidate_iso(o, 0);
if(ret<=0)
burn_drive_cancel(drive);
return;
}
}
burn_disc_erase(drive, fast);
}
int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba)
{
int ret;
struct isoburn *o;
#ifdef Hardcoded_cd_rW
/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
*start_lba= Hardcoded_cd_rw_c1;
return(1);
#endif
if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE &&
isoburn_disc_get_status(d)!=BURN_DISC_FULL)
return(0);
ret= isoburn_find_emulator(&o, d, 0);
if(ret<0)
return(0);
if(ret>0) if(o->emulation_mode>0) {
*start_lba= 0;
return(1);
}
return(burn_disc_get_msc1(d, start_lba));
}
int isoburn_disc_track_lba_nwa(struct burn_drive *d,
struct burn_write_opts *opts,
int trackno, int *lba, int *nwa)
{
int ret;
struct isoburn *o;
#ifdef Hardcoded_cd_rW
/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
*lba= Hardcoded_cd_rw_c1;
*nwa= Hardcoded_cd_rw_nwA;
return(1);
#endif
*nwa= *lba= 0;
ret= isoburn_find_emulator(&o, d, 0);
if(ret<0)
return(0);
if(ret>0) if(o->emulation_mode>0) {
*lba= 0;
*nwa= o->nwa;
return(1);
}
if(burn_drive_get_drive_role(d) != 1)
return(1);
return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa));
}
void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
{
int ret;
struct isoburn *o;
struct burn_drive *drive;
char reasons[BURN_REASONS_LEN],msg[160+BURN_REASONS_LEN];
enum burn_write_types write_type;
drive= burn_write_opts_get_drive(opts);
ret= isoburn_find_emulator(&o, drive, 0);
if(ret<0)
return;
if(o!=NULL) {
o->wrote_well= -1;
if(o->emulation_mode!=0) {
burn_write_opts_set_multi(opts, 0);
if(o->emulation_mode>0 && o->nwa >= 0)
burn_write_opts_set_start_byte(opts, ((off_t) o->nwa) * (off_t) 2048);
}
}
write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
if (write_type == BURN_WRITE_NONE) {
sprintf(msg, "Failed to find a suitable write mode:\n%s", reasons);
burn_msgs_submit(0, msg, 0, "SORRY", NULL);
if(o!=NULL)
o->wrote_well= 0;
/* To cause a negative reply with burn_drive_wrote_well() */
burn_drive_cancel(drive);
return;
}
/*
sprintf(reasons, "%d", (int) write_type);
fprintf(stderr, "isoburn_EXPERIMENTAL: write_type = %s\n",
(write_type == BURN_WRITE_SAO ? "SAO" :
(write_type == BURN_WRITE_TAO ? "TAO" : reasons)));
*/
#ifdef Hardcoded_cd_rW
/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA);
burn_write_opts_set_start_byte(opts,
((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048);
#endif
burn_disc_write(opts, disc);
}
void isoburn_drive_release(struct burn_drive *drive, int eject)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, drive, 0);
if(ret<0)
return;
if(o!=NULL) {
isoburn_destroy(&o, 0);
}
burn_drive_release(drive, eject);
}
void isoburn_finish(void)
{
isoburn_destroy_all(&isoburn_list_start, 0);
burn_finish();
iso_finish();
}
int isoburn_needs_emulation(struct burn_drive *drive)
{
int ret;
struct isoburn *o;
enum burn_disc_status s;
s= isoburn_disc_get_status(drive);
if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE)
return(-1);
ret= isoburn_find_emulator(&o, drive, 0);
if(ret<0)
return(-1);
if(ret>0)
if(o->emulation_mode>0)
return(1);
return(0);
}
int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag)
{
int ret;
struct burn_drive *drive = o->drive;
struct burn_multi_caps *caps= NULL;
ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
if(ret<=0)
goto ex;
if(!caps->start_adr)
{ret= 0; goto ex;}
o->min_start_byte= value;
if(value % caps->start_alignment)
value+= caps->start_alignment - (value % caps->start_alignment);
o->nwa= value/2048;
/* If suitable for alignment, round up to full 16 sector addresses */
if((o->nwa%16) && ((16*2048) % caps->start_alignment)==0 )
o->nwa+= 16 - (o->nwa%16);
ret= 1;
ex:
if(caps!=NULL)
burn_disc_free_multi_caps(&caps);
return(ret);
}
int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
int flag)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, d, 0);
if(ret<0)
return(-1);
if(ret==0)
return(0);
*start_byte= o->min_start_byte;
if(o->min_start_byte<=0)
return(0);
return(1);
}
int isoburn_drive_wrote_well(struct burn_drive *d)
{
int ret;
struct isoburn *o;
ret= isoburn_find_emulator(&o, d, 0);
if(ret<0)
return(-1);
if(o!=NULL)
if(o->wrote_well>=0)
return(o->wrote_well);
ret= burn_drive_wrote_well(d);
return ret;
}
int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
char **status_text)
{
int ret;
struct isoburn *o;
#ifdef Libisoburn_no_fifO
size_t hsize= 0, hfree_bytes= 0;
#endif
ret= isoburn_find_emulator(&o, d, 0);
if(ret<0)
return(-1);
#ifdef Libisoburn_no_fifO
if(o==NULL)
return(-1);
if(o->iso_source==NULL)
return(-1);
ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes);
if(hsize > 1024*1024*1024)
*size= 1024*1024*1024;
else
*size= hsize;
if(hfree_bytes > 1024*1024*1024)
*free_bytes= 1024*1024*1024;
else
*free_bytes= hfree_bytes;
*status_text= "";
if(ret==0)
*status_text= "standby";
else if(ret==1)
*status_text= "active";
else if(ret==2)
*status_text= "ending";
else if(ret==3)
*status_text= "failing";
else if(ret==4)
*status_text= "unused";
else if(ret==5)
*status_text= "abandoned";
else if(ret==6)
*status_text= "ended";
else if(ret==7)
*status_text= "aborted";
#else
if(o==NULL)
return(0);
if(o->fifo==NULL)
return(0);
ret= burn_fifo_inquire_status(o->fifo, size, free_bytes, status_text);
#endif /* ! Libisoburn_no_fifO */
return(ret);
}
/* <<< to be replaced by libburn-0.4.3 API call burn_sev_to_text().
This is a copy of libdax_msgs__sev_to_text() which is not exposed
by the API of of libburn-0.4.2 . As soon as xorriso gets based on
libburn-0.4.4 this redundancy is to be removed.
It is safe, nevertheless, because the severity codes are eternal.
*/
#define LIBDAX_MSGS_SEV_ALL 0x00000000
#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
#define LIBDAX_MSGS_SEV_NOTE 0x30000000
#define LIBDAX_MSGS_SEV_HINT 0x40000000
#define LIBDAX_MSGS_SEV_WARNING 0x50000000
#define LIBDAX_MSGS_SEV_SORRY 0x60000000
#define LIBDAX_MSGS_SEV_FAILURE 0x68000000
#define LIBDAX_MSGS_SEV_FATAL 0x70000000
#define LIBDAX_MSGS_SEV_ABORT 0x71000000
#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
int isoburn__sev_to_text(int severity, char **severity_name,
int flag)
{
if(flag&1) {
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
return(1);
}
*severity_name= "";
if(severity>=LIBDAX_MSGS_SEV_NEVER)
*severity_name= "NEVER";
else if(severity>=LIBDAX_MSGS_SEV_ABORT)
*severity_name= "ABORT";
else if(severity>=LIBDAX_MSGS_SEV_FATAL)
*severity_name= "FATAL";
else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
*severity_name= "FAILURE";
else if(severity>=LIBDAX_MSGS_SEV_SORRY)
*severity_name= "SORRY";
else if(severity>=LIBDAX_MSGS_SEV_WARNING)
*severity_name= "WARNING";
else if(severity>=LIBDAX_MSGS_SEV_HINT)
*severity_name= "HINT";
else if(severity>=LIBDAX_MSGS_SEV_NOTE)
*severity_name= "NOTE";
else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
*severity_name= "UPDATE";
else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
*severity_name= "DEBUG";
else if(severity>=LIBDAX_MSGS_SEV_ALL)
*severity_name= "ALL";
else {
*severity_name= "";
return(0);
}
return(1);
}
int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
char min_severity[], int flag)
{
int error_code, iso_sev, min_sev, ret;
char *sev_text_pt, *msg_text_pt= NULL;
/* <<< delete as soon as replacement appears in libisofs */
#define ISO_ERR_CODE(e) (e & 0x0000FFFF)
error_code= 0x00050000 | ISO_ERR_CODE(iso_error_code);
if(iso_error_code<0)
msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
if(msg_text_pt==NULL)
msg_text_pt= msg_text;
iso_sev= iso_error_get_severity(iso_error_code);
sev_text_pt= min_severity;
burn_text_to_sev(min_severity, &min_sev, 0);
if(min_sev < iso_sev)
/* >>> with libburn-0.4.4 do: burn_sev_to_text(iso_sev, &sev_text_pt, 0); */
isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
ret= burn_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, NULL);
return(ret);
}