libisoburn/xorriso/xorrisoburn.c

4602 lines
141 KiB
C

/* Adapter to libisoburn, libisofs and libburn for xorriso,
a command line oriented batch and dialog tool which creates, loads,
manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2008 Thomas Schmitt, <scdbackup@gmx.net>
Provided under GPL version 2.
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#define Xorriso_on_libisofs_after_0_6_2 yes
/* ------------------------------------------------------------------------ */
#ifndef Xorriso_standalonE
/* The library which does the ISO 9660 / RockRidge manipulations */
#include <libisofs/libisofs.h>
/* The library which does MMC optical drive operations */
#include <libburn/libburn.h>
/* The library which enhances overwriteable media with ISO 9660 multi-session
capabilities via the method invented by Andy Polyakov for growisofs */
#include <libisoburn/libisoburn.h>
/* The official xorriso options API. "No shortcuts" */
#include "xorriso.h"
/* The inner description of XorrisO */
#include "xorriso_private.h"
/* The inner isofs- and burn-library interface */
#include "xorrisoburn.h"
#else /* ! Xorriso_standalonE */
#include "../libisofs/libisofs.h"
#include "../libburn/libburn.h"
#include "../libisoburn/libisoburn.h"
#include "xorriso.h"
#include "xorriso_private.h"
#include "xorrisoburn.h"
#endif /* Xorriso_standalonE */
int Xorriso_pacifier_loop(struct XorrisO *xorriso, struct burn_drive *drive,
int flag);
int Xorriso__read_pacifier(IsoImage *image, IsoFileSource *filesource);
#define LIBISO_ISDIR(node) (iso_node_get_type(node) == LIBISO_DIR)
#define LIBISO_ISREG(node) (iso_node_get_type(node) == LIBISO_FILE)
#define LIBISO_ISLNK(node) (iso_node_get_type(node) == LIBISO_SYMLINK)
#define LIBISO_ISCHR(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
S_ISCHR(iso_node_get_mode(node)))
#define LIBISO_ISBLK(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
S_ISBLK(iso_node_get_mode(node)))
#define LIBISO_ISFIFO(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
S_ISFIFO(iso_node_get_mode(node)))
#define LIBISO_ISSOCK(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
S_ISSOCK(iso_node_get_mode(node)))
/* CD specs say one shall not write tracks < 600 kiB */
#define Xorriso_cd_min_track_sizE 300
/* ------------------------------------------------------------------------ */
int Xorriso_startup_libraries(struct XorrisO *xorriso, int flag)
{
int ret, major, minor, micro;
char *handler_prefix= NULL;
char *queue_sev, *print_sev, reason[1024];
/* First an ugly compile time check for header version compatibility.
If everthing matches, then no C code is produced. In case of mismatch,
intentionally faulty C code will be inserted.
*/
/* The minimum requirement of xorriso towards the libisoburn header
at compile time is defined in xorriso/xorrisoburn.h
xorriso_libisoburn_req_major
xorriso_libisoburn_req_minor
xorriso_libisoburn_req_micro
It gets compared against the version macros in libburn/libburn.h :
isoburn_header_version_major
isoburn_header_version_minor
isoburn_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: 'LIBISOBURN_MISCONFIGURATION' undeclared (first use in this function)
error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisoburn_dot_h_TOO_OLD__SEE_xorrisoburn_dot_c' undeclared (first use in this function)
error: 'LIBISOBURN_MISCONFIGURATION_' undeclared (first use in this function)
*/
/* The indendation is an advise of man gcc to help old compilers ignoring */
#if xorriso_libisoburn_req_major > isoburn_header_version_major
#define Isoburn_libisoburn_dot_h_too_olD 1
#endif
#if xorriso_libisoburn_req_major == isoburn_header_version_major && xorriso_libisoburn_req_minor > isoburn_header_version_minor
#define Isoburn_libisoburn_dot_h_too_olD 1
#endif
#if xorriso_libisoburn_req_minor == isoburn_header_version_minor && xorriso_libisoburn_req_micro > isoburn_header_version_micro
#define Isoburn_libisoburn_dot_h_too_olD 1
#endif
#ifdef Isoburn_libisoburn_dot_h_too_olD
LIBISOBURN_MISCONFIGURATION = 0;
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisoburn_dot_h_TOO_OLD__SEE_xorrisoburn_dot_c = 0;
LIBISOBURN_MISCONFIGURATION_ = 0;
#endif
/* End of ugly compile time test (scroll up for explanation) */
sprintf(xorriso->info_text, "Starting up libraries ...\n");
Xorriso_info(xorriso, 0);
handler_prefix= calloc(strlen(xorriso->progname)+3+1, 1);
if(handler_prefix==NULL) {
sprintf(xorriso->info_text,
"Cannot allocate memory for initializing libraries");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
reason[0]= 0;
ret= isoburn_initialize(reason, 0);
if(ret==0) {
sprintf(xorriso->info_text, "Cannot initialize libraries");
if(reason[0])
sprintf(xorriso->info_text+strlen(xorriso->info_text),
". Reason given:\n%s", reason);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
free(handler_prefix);
return(0);
}
ret= isoburn_is_compatible(isoburn_header_version_major,
isoburn_header_version_minor,
isoburn_header_version_micro, 0);
if(ret<=0) {
isoburn_version(&major, &minor, &micro);
sprintf(xorriso->info_text,
"libisoburn version too old: %d.%d.%d . Need at least: %d.%d.%d .\n",
major, minor, micro,
isoburn_header_version_major, isoburn_header_version_minor,
isoburn_header_version_micro);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
xorriso->libs_are_started= 1;
queue_sev= "ALL";
if(xorriso->library_msg_direct_print) {
/* >>> need option for controlling this in XorrisO.
See also Xorriso_msgs_submit */;
print_sev= xorriso->report_about_text;
} else
print_sev= "NEVER";
iso_set_msgs_severities(queue_sev, print_sev, "libsofs : ");
burn_msgs_set_severities(queue_sev, print_sev, "libburn : ");
/* ??? >>> do we want united queues ? */
/* burn_set_messenger(iso_get_messenger()); */
sprintf(handler_prefix, "%s : ", xorriso->progname);
burn_set_signal_handling(handler_prefix, NULL, 0);
Xorriso_process_msg_queues(xorriso,0);
if(reason[0]) {
sprintf(xorriso->info_text, "%s", reason);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
}
sprintf(xorriso->info_text, "Library startup done.\n");
Xorriso_info(xorriso, 0);
free(handler_prefix);
return(1);
}
/* @param flag bit0= global shutdown of libraries */
int Xorriso_detach_libraries(struct XorrisO *xorriso, int flag)
{
Xorriso_give_up_drive(xorriso, 3);
if(xorriso->in_volset_handle!=NULL) { /* standalone image */
iso_image_unref((IsoImage *) xorriso->in_volset_handle);
xorriso->in_volset_handle= NULL;
}
if(flag&1) {
if(xorriso->libs_are_started==0)
return(0);
isoburn_finish();
}
return(1);
}
/* @param flag bit1= obtain outdrive, else indrive */
int Xorriso_get_drive_handles(struct XorrisO *xorriso,
struct burn_drive_info **dinfo,
struct burn_drive **drive,
char *attempt, int flag)
{
if(flag&2)
*dinfo= (struct burn_drive_info *) xorriso->out_drive_handle;
else
*dinfo= (struct burn_drive_info *) xorriso->in_drive_handle;
if(*dinfo==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text, "No %s drive aquired %s",
(flag&2 ? "output" : "input"), attempt);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
*drive= (*dinfo)[0].drive;
return((*drive)!=NULL);
}
/* >>> todo: throw out the copies of libdax_msgs entrails */
/* <<< 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_ERRFILE 0x08000000
#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_MISHAP 0x64000000
#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 Xorriso__sev_to_text(int severity, char **severity_name,
int flag)
{
#ifdef Xorriso_on_libisofs_after_0_6_2
int ret;
#else
#ifdef Xorriso_on_libburn_after_0_4_2
int ret;
#endif
#endif
#ifdef Xorriso_on_libisofs_after_0_6_2
ret= iso_sev_to_text(severity, severity_name);
if(ret>0)
return(ret);
#endif /* Xorriso_on_libisofs_after_0_6_2 */
#ifdef Xorriso_on_libburn_after_0_4_2
ret= burn_sev_to_text(severity, severity_name, 0);
if(ret>0)
return(ret);
#endif
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_MISHAP)
*severity_name= "MISHAP";
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_ERRFILE)
*severity_name= "ERRFILE";
else if(severity>=LIBDAX_MSGS_SEV_ALL)
*severity_name= "ALL";
else {
*severity_name= "";
return(0);
}
return(1);
}
int Xorriso__text_to_sev(char *severity_name, int *severity_number, int flag)
{
int ret= 1;
#ifdef Xorriso_on_libisofs_after_0_6_2
ret= iso_text_to_sev(severity_name, severity_number);
if(ret>0)
return(ret);
#endif /* Xorriso_on_libisofs_after_0_6_2 */
#ifndef Xorriso_on_libburn_after_0_4_2
if(severity_name[0]==0)
*severity_number= 0;
else if(strcmp(severity_name, "MISHAP")==0)
*severity_number= LIBDAX_MSGS_SEV_MISHAP;
else if(strcmp(severity_name, "ERRFILE")==0)
*severity_number= LIBDAX_MSGS_SEV_ERRFILE;
else
#endif /* ! Xorriso_on_libburn_after_0_4_2 */
ret= burn_text_to_sev(severity_name, severity_number, 0);
return(ret);
}
/* @param flag bit0= report libisofs error text
bit1= victim is disk_path
*/
int Xorriso_report_iso_error(struct XorrisO *xorriso, char *victim,
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;
char sfe[6*SfileadrL];
static int sorry_sev= -1;
if(sorry_sev<0)
Xorriso__text_to_sev("SORRY", &sorry_sev, 0);
error_code= iso_error_get_code(iso_error_code);
if(error_code < 0x00030000 || error_code >= 0x00040000)
error_code= (error_code & 0xffff) | 0x00050000;
if(flag&1)
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);
if(iso_sev >= sorry_sev && (flag & 2) && victim[0])
Xorriso_msgs_submit(xorriso, 0, victim, 0, "ERRFILE", 0);
sev_text_pt= min_severity;
Xorriso__text_to_sev(min_severity, &min_sev, 0);
if(min_sev < iso_sev)
Xorriso__sev_to_text(iso_sev, &sev_text_pt, 0);
strcpy(sfe, msg_text_pt);
if(victim[0]) {
strcat(sfe, ": ");
Text_shellsafe(victim, sfe+strlen(sfe), 0);
}
ret= Xorriso_msgs_submit(xorriso, error_code, sfe, os_errno, sev_text_pt, 4);
return(ret);
}
/* @param flag bit0= suppress messages below UPDATE
bit1= suppress messages below FAILURE
*/
int Xorriso_set_image_severities(struct XorrisO *xorriso, int flag)
{
char *queue_sev, *print_sev;
if(flag&2)
queue_sev= "FAILURE";
else if(flag&1)
queue_sev= "UPDATE";
else
queue_sev= "ALL";
if(xorriso->library_msg_direct_print)
print_sev= xorriso->report_about_text;
else
print_sev= "NEVER";
iso_set_msgs_severities(queue_sev, print_sev, "libisofs : ");
return(1);
}
int Xorriso_update_volid(struct XorrisO *xorriso, int flag)
{
int gret, sret= 1;
gret= Xorriso_get_volid(xorriso, xorriso->loaded_volid, 0);
if(gret<=0 || (!xorriso->volid_default) || xorriso->loaded_volid[0]==0)
sret= Xorriso_set_volid(xorriso, xorriso->volid, 1);
return(gret>0 && sret>0);
}
int Xorriso_create_empty_iso(struct XorrisO *xorriso, int flag)
{
int ret;
IsoImage *volset;
struct isoburn_read_opts *ropts;
struct burn_drive_info *dinfo= NULL;
struct burn_drive *drive= NULL;
if(xorriso->out_drive_handle != NULL) {
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to attach volset to drive", 2);
if(ret<=0)
return(ret);
}
if(xorriso->in_volset_handle!=NULL) {
iso_image_unref((IsoImage *) xorriso->in_volset_handle);
xorriso->in_volset_handle= NULL;
xorriso->loaded_volid[0]= 0;
xorriso->volset_change_pending= 0;
}
ret= isoburn_ropt_new(&ropts, 0);
if(ret<=0)
return(ret);
/* Note: no return before isoburn_ropt_destroy() */
isoburn_ropt_set_extensions(ropts, isoburn_ropt_pretend_blank);
isoburn_ropt_set_input_charset(ropts, NULL);
isoburn_set_read_pacifier(drive, NULL, NULL);
ret= isoburn_read_image(drive, ropts, &volset);
Xorriso_process_msg_queues(xorriso,0);
isoburn_ropt_destroy(&ropts, 0);
if(ret<=0) {
sprintf(xorriso->info_text, "Failed to create new empty ISO image object");
Xorriso_report_iso_error(xorriso, "", ret, xorriso->info_text, 0, "FATAL",
0);
return(-1);
}
xorriso->in_volset_handle= (void *) volset;
Xorriso_update_volid(xorriso, 0);
xorriso->volset_change_pending= 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
@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;
uint32_t size;
struct burn_drive_info *dinfo= NULL, *out_dinfo, *in_dinfo;
struct burn_drive *drive, *out_drive, *in_drive;
enum burn_disc_status state;
IsoImage *volset = NULL;
struct isoburn_read_opts *ropts= NULL;
char adr_data[SfileadrL], *libburn_adr, *boot_fate;
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);
libburn_adr= adr;
if(strcmp(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(adr_data, "stdio:/dev/fd/%d", xorriso->dev_fd_1);
libburn_adr= adr_data;
}
}
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;
} 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 indev with outdev", 0);
if(ret<=0)
goto ex;
ret= burn_drive_equals_adr(in_drive, libburn_adr, 1);
if(ret==1)
dinfo= in_dinfo;
}
if(dinfo==NULL) {
ret= isoburn_drive_aquire(&dinfo, libburn_adr, 1|((flag&(8|4))>>1));
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;
}
}
drive= dinfo[0].drive;
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, "WARNING", 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;}
}
}
Xorriso_toc(xorriso, 1|2);
{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;
/* 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");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
{ret= 0; goto ex;}
}
/* fill read opts */
ret= isoburn_ropt_new(&ropts, 0);
if(ret<=0)
goto ex;
isoburn_ropt_set_extensions(ropts, isoburn_ropt_noiso1999);
isoburn_ropt_set_default_perms(ropts, (uid_t) 0, (gid_t) 0, (mode_t) 0555);
isoburn_ropt_set_input_charset(ropts, NULL);
Xorriso_set_image_severities(xorriso, 1); /* No DEBUG messages */
Xorriso_pacifier_reset(xorriso, 0);
isoburn_set_read_pacifier(drive, Xorriso__read_pacifier, (void *) xorriso);
if(isoburn_read_image(drive, ropts, &volset) <= 0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_set_image_severities(xorriso, 0);
sprintf(xorriso->info_text,"Cannot read ISO image volset");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 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_set_image_severities(xorriso, 0);
Xorriso_update_volid(xorriso, 0);
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->patch_isolinux_image)
boot_fate= "patched as isolinux image";
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_toc(xorriso, 1);
if(xorriso->loaded_volid[0]!=0) {
sprintf(xorriso->result_line,"Volume id : '%s'\n",xorriso->loaded_volid);
Xorriso_result(xorriso,0);
if(strcmp(xorriso->loaded_volid, xorriso->volid)!=0 &&
!xorriso->volid_default) {
sprintf(xorriso->result_line, "New volume id: '%s'\n", xorriso->volid);
Xorriso_result(xorriso,0);
}
}
ret= 1+not_writeable;
ex:
Xorriso_process_msg_queues(xorriso,0);
if(ret<=0) {
hret= Xorriso_give_up_drive(xorriso, flag&3);
if(hret<ret)
ret= hret;
}
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;
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) {
if(drive!=NULL && !in_is_out_too)
isoburn_drive_release(drive,!!(flag&4));
if(dinfo!=NULL && !in_is_out_too)
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;
xorriso->loaded_volid[0]= 0;
xorriso->volset_change_pending= 0;
in_is_out_too= 0;
}
if((flag&2) && xorriso->out_drive_handle!=NULL) {
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,!!(flag&4));
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);
}
}
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_make_write_options(
struct XorrisO *xorriso, struct burn_drive *drive,
struct burn_write_opts **burn_options, int flag)
{
int drive_role;
*burn_options= burn_write_opts_new(drive);
if(*burn_options==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Cannot allocate option set");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
burn_write_opts_set_simulate(*burn_options, !!xorriso->do_dummy);
drive_role= burn_drive_get_drive_role(drive);
burn_write_opts_set_multi(*burn_options,
!(xorriso->do_close || drive_role==0 || drive_role==3));
burn_drive_set_speed(drive, xorriso->speed, xorriso->speed);
burn_write_opts_set_underrun_proof(*burn_options, 1);
return(1);
}
/* @param flag bit0= do not write but only prepare and return size in sectors
bit1= do not use isoburn wrappers
*/
int Xorriso_sanitize_image_size(struct XorrisO *xorriso,
struct burn_drive *drive, struct burn_disc *disc,
struct burn_write_opts *burn_options, int flag)
{
int ret, img_sectors, num_sessions= 0, num_tracks= 0, padding= 0, profile;
int media_space;
char profile_name[80];
struct burn_session **sessions;
struct burn_track **tracks;
img_sectors= burn_disc_get_sectors(disc);
sessions= burn_disc_get_sessions(disc, &num_sessions);
if(sessions==NULL || num_sessions < 1) {
no_track:;
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Program error : no track in prepared disc");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
{ret= -1; goto ex;}
}
tracks= burn_session_get_tracks(sessions[0], &num_tracks);
if(tracks==NULL || num_tracks < 1)
goto no_track;
padding= 0;
ret= burn_disc_get_profile(drive, &profile, profile_name);
padding= xorriso->padding / 2048;
if(xorriso->padding > padding * 2048)
padding++;
if(img_sectors>0 && (profile==0x09 || profile==0x0a)) { /* CD-R , CD-RW */
if(img_sectors + padding < Xorriso_cd_min_track_sizE) {
padding= Xorriso_cd_min_track_sizE - img_sectors;
sprintf(xorriso->info_text,
"Expanded track to minimum size of %d sectors",
Xorriso_cd_min_track_sizE);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
}
burn_track_define_data(tracks[0], 0, padding * 2048, 0, BURN_MODE1);
Xorriso_process_msg_queues(xorriso,0);
if(flag&2)
media_space= burn_disc_available_space(drive, burn_options) /
(off_t) 2048;
else
media_space= isoburn_disc_available_space(drive, burn_options) /
(off_t) 2048;
if(media_space < img_sectors + padding) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Image size %ds exceeds free space on media %ds",
img_sectors + padding, media_space);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
if(flag&1) {
ret= img_sectors+padding;
} else
ret= 1;
ex:;
return(ret);
}
/* @param flag bit0= do not write but only prepare and return size in sectors
*/
int Xorriso_write_session(struct XorrisO *xorriso, int flag)
{
int ret, relax= 0, i;
int major, minor, micro;
char xorriso_id[256], *img_id;
struct isoburn_imgen_opts *sopts= NULL;
struct burn_drive_info *dinfo, *source_dinfo;
struct burn_drive *drive, *source_drive;
struct burn_disc *disc= NULL;
struct burn_write_opts *burn_options;
off_t readcounter= 0,writecounter= 0;
int num_sessions= 0, num_tracks= 0;
struct burn_session **sessions;
struct burn_track **tracks;
enum burn_disc_status s;
IsoImage *image = NULL;
ElToritoBootImage *bootimg;
#ifdef NIX
char profile_name[80];
int padding= 0, img_sectors, media_space, profile;
#endif
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to write", 2);
if(ret<=0)
return(0);
if(xorriso->out_drive_handle == xorriso->in_drive_handle) {
source_drive= drive;
} else {
if(xorriso->in_drive_handle == NULL) {
source_drive= drive;
} else {
ret= Xorriso_get_drive_handles(xorriso, &source_dinfo, &source_drive,
"on attempt to get source for write", 0);
if(ret<=0)
goto ex;
}
s= isoburn_disc_get_status(drive);
if(s!=BURN_DISC_BLANK) {
s= burn_disc_get_status(drive);
if(s!=BURN_DISC_BLANK)
sprintf(xorriso->info_text,
"-indev differs from -outdev and -outdev media is not blank");
else
sprintf(xorriso->info_text,
"-indev differs from -outdev and -outdev media holds valid ISO image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
}
ret= isoburn_igopt_new(&sopts, 0);
if(ret<=0)
return(ret);
relax= isoburn_igopt_allow_deep_paths;
/* Adjust or discard boot image */
image= isoburn_get_attached_image(source_drive);
/* >>> ??? move down to libisoburn ? */
if(image!=NULL && !(flag&1)) {
ret= iso_image_get_boot_image(image, &bootimg, NULL, NULL);
if(xorriso->patch_isolinux_image) {
if(ret==1) {
relax|= isoburn_igopt_allow_full_ascii;
sprintf(xorriso->info_text, "Patching alleged isolinux boot image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
el_torito_patch_isolinux_image(bootimg);
} else {
sprintf(xorriso->info_text,
"Could not find any boot image for -boot_image isolinux patch");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
}
} else if(xorriso->keep_boot_image && ret==1) {
relax|= isoburn_igopt_allow_full_ascii;
sprintf(xorriso->info_text, "Keeping boot image unchanged");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
} else if(ret==1) {
iso_image_remove_boot_image(image);
sprintf(xorriso->info_text, "Discarded boot image from old session");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
}
isoburn_igopt_set_level(sopts, 2);
isoburn_igopt_set_extensions(sopts, 1|((!!xorriso->do_joliet)<<1));
isoburn_igopt_set_relaxed(sopts, isoburn_igopt_allow_deep_paths);
isoburn_igopt_set_sort_files(sopts, 1);
isoburn_igopt_set_over_mode(sopts, 0, 0, (mode_t) 0, (mode_t) 0);
isoburn_igopt_set_over_ugid(sopts, 0, 0, (uid_t) 0, (gid_t) 0);
isoburn_igopt_set_out_charset(sopts, NULL);
isoburn_igopt_set_fifo_size(sopts, xorriso->fs * 2048);
if(image!=NULL &&
strlen(Xorriso_program_versioN)+strlen(Xorriso_timestamP)<80) {
sprintf(xorriso_id, "XORRISO-%s %s",
Xorriso_program_versioN, Xorriso_timestamP);
isoburn_version(&major, &minor, &micro);
if(strlen(xorriso_id)<80)
sprintf(xorriso_id+strlen(xorriso_id),
", LIBISOBURN-%d.%d.%d", major, minor, micro);
iso_lib_version(&major, &minor, &micro);
if(strlen(xorriso_id)<80)
sprintf(xorriso_id+strlen(xorriso_id),
", LIBISOFS-%d.%d.%d", major, minor, micro);
burn_version(&major, &minor, &micro);
if(strlen(xorriso_id)<80)
sprintf(xorriso_id+strlen(xorriso_id),
", LIBBURN-%d.%d.%d", major, minor, micro);
xorriso_id[128]= 0;
img_id= (char *) iso_image_get_data_preparer_id(image);
if(img_id!=NULL) {
for(i= strlen(img_id)-1; i>=0 && img_id[i]==' '; i--);
if(i>0) {
sprintf(xorriso->info_text, "Overwrote previous preparer id '%s'",
img_id);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
}
}
iso_image_set_data_preparer_id(image, xorriso_id);
}
/* Make final abort check before starting expensive activities */
ret= Xorriso_eval_problem_status(xorriso, 1, 0);
if(ret<0)
{ret= 0; goto ex;}
Xorriso_set_abort_severity(xorriso, 1);
if(xorriso->out_drive_handle == xorriso->in_drive_handle ||
xorriso->in_drive_handle == NULL) {
ret= isoburn_prepare_disc(source_drive, &disc, sopts);
} else {
ret= isoburn_prepare_new_image(source_drive, &disc, sopts, drive);
}
if (ret <= 0) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Failed to prepare session write run");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
if(ret<=0)
goto ex;
#ifndef NIX
ret= Xorriso_sanitize_image_size(xorriso, drive, disc, burn_options, flag&1);
if(ret<=0 || (flag&1)) {
Xorriso_process_msg_queues(xorriso,0);
if(flag&1) /* set queue severity to FAILURE */
Xorriso_set_image_severities(xorriso, 2);
isoburn_cancel_prepared_write(source_drive, drive, 0);
if(flag&1) /* reset queue severity */
Xorriso_set_image_severities(xorriso, 0);
goto ex;
}
#else
ret= img_sectors= burn_disc_get_sectors(disc);
if(flag&1)
goto ex;
sessions= burn_disc_get_sessions(disc, &num_sessions);
if(sessions==NULL || num_sessions < 1) {
no_track:;
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Program error : no track in prepared disc");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
isoburn_cancel_prepared_write(source_drive, drive, 0);
{ret= -1; goto ex;}
}
tracks= burn_session_get_tracks(sessions[0], &num_tracks);
if(tracks==NULL || num_tracks < 1)
goto no_track;
padding= 0;
ret= burn_disc_get_profile(drive, &profile, profile_name);
padding= xorriso->padding / 2048;
if(xorriso->padding > padding * 2048)
padding++;
if(profile==0x09 || profile==0x0a) { /* CD-R , CD-RW */
if(img_sectors + padding < Xorriso_cd_min_track_sizE) {
padding= Xorriso_cd_min_track_sizE - img_sectors;
sprintf(xorriso->info_text,
"Expanded track to minimum size of %d sectors",
Xorriso_cd_min_track_sizE);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
}
burn_track_define_data(tracks[0], 0, padding * 2048, 0, BURN_MODE1);
Xorriso_process_msg_queues(xorriso,0);
media_space= isoburn_disc_available_space(drive, burn_options) / (off_t) 2048;
if(media_space < img_sectors + padding) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Image size %ds exceeds free space on media %ds",
img_sectors + padding, media_space);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
isoburn_cancel_prepared_write(source_drive, drive, 0);
{ret= 0; goto ex;}
}
#endif /* NIX */
xorriso->run_state= 1; /* Indicate that burning has started */
isoburn_disc_write(burn_options, disc);
burn_write_opts_free(burn_options);
ret= Xorriso_pacifier_loop(xorriso, drive, 0);
if(ret<=0)
goto ex;
if(!isoburn_drive_wrote_well(drive)) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"libburn indicates failure with writing.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
sessions= burn_disc_get_sessions(disc, &num_sessions);
if(num_sessions>0) {
tracks= burn_session_get_tracks(sessions[0], &num_tracks);
if(tracks!=NULL && num_tracks>0) {
burn_track_get_counters(tracks[0],&readcounter,&writecounter);
sprintf(xorriso->info_text,
"ISO image produced: %d sectors. Written to media: %d sectors\n",
(int) (readcounter/ (off_t) 2048),
(int) (writecounter/ (off_t) 2048));
Xorriso_info(xorriso, 0);
}
}
ret= isoburn_activate_session(drive);
Xorriso_process_msg_queues(xorriso,0);
if(ret<=0) {
sprintf(xorriso->info_text,
"Could not write new set of volume descriptors");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
goto ex;
}
/* Done early to free any reference to the libisofs resources via disc */
if(disc!=NULL)
burn_disc_free(disc);
disc= NULL;
/* To wait for the end of the libisofs threads and their messages. */
isoburn_sync_after_write(source_drive, drive, 0);
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text, "Writing completed sucessfully.\n\n");
Xorriso_info(xorriso, 0);
ret= 1;
ex:;
xorriso->run_state= 0; /* Indicate that burning has ended */
Xorriso_set_abort_severity(xorriso, 0);
if(ret<=0) {
/* >>> ??? revive discarded boot image */;
}
if(disc!=NULL)
burn_disc_free(disc);
isoburn_igopt_destroy(&sopts, 0);
Xorriso_process_msg_queues(xorriso,0);
return(ret);
}
int Xorriso_check_burn_abort(struct XorrisO *xorriso, int flag)
{
int ret;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
if(xorriso->run_state!=1)
return(0);
ret= Xorriso_eval_problem_status(xorriso, 1, 1);
if(ret>=0)
return(0);
sprintf(xorriso->info_text,
"-abort_on '%s' encountered '%s' during image writing",
xorriso->abort_on_text, xorriso->problem_status_text);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0,
xorriso->problem_status_text, 0);
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to abort burn run", 2);
if(ret<=0)
return(0);
burn_drive_cancel(drive);
sprintf(xorriso->info_text,
"libburn has now been urged to cancel its operation");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(1);
}
/* This loop watches burn runs until they end.
It issues pacifying update messages to the user.
@param flag bit0-3 = emulation mode
0= xorriso
1= cdrskin
bit4= report speed in CD units
*/
int Xorriso_pacifier_loop(struct XorrisO *xorriso, struct burn_drive *drive,
int flag)
{
int ret, size, free_bytes, i, aborting= 0, emul, buffer_fill= 50, last_sector;
struct burn_progress progress;
char *status_text;
enum burn_drive_status drive_status;
double start_time, current_time, last_time;
double measured_speed, speed_factor= 1385000;
start_time= Sfile_microtime(0);
while(burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
usleep(100002);
emul= flag&15;
if(flag&16)
speed_factor= 150.0*1024;
progress.sector= 0;
current_time= Sfile_microtime(0);
while(1) {
last_time= current_time;
last_sector= progress.sector;
drive_status= burn_drive_get_status(drive, &progress);
if(drive_status == BURN_DRIVE_IDLE)
break;
current_time= Sfile_microtime(0);
if(drive_status == BURN_DRIVE_WRITING && progress.sectors > 0) {
if(emul==1) {
if(progress.sector<=progress.sectors)
sprintf(xorriso->info_text, "%4d of %4d MB written",
progress.sector / 512, progress.sectors / 512);
else
sprintf(xorriso->info_text, "%4d MB written",
progress.sector / 512);
if(xorriso->pacifier_fifo!=NULL) {
ret= burn_fifo_inquire_status(xorriso->pacifier_fifo,
&size, &free_bytes, &status_text);
if(ret>0 )
sprintf(xorriso->info_text+strlen(xorriso->info_text),
" (fifo %2d%%)",
(int) (100.0-100.0*((double) free_bytes)/(double) size));
}
buffer_fill= 50;
if(progress.buffer_capacity>0)
buffer_fill= (double) (progress.buffer_capacity
- progress.buffer_available) * 100.0
/ (double) progress.buffer_capacity;
sprintf(xorriso->info_text+strlen(xorriso->info_text), " [buf %3d%%]",
buffer_fill);
if(current_time-last_time>0.2) {
measured_speed= (progress.sector - last_sector) * 2048.0 /
(current_time - last_time);
sprintf(xorriso->info_text+strlen(xorriso->info_text), " %4.1fx.",
measured_speed/speed_factor);
}
} else {
if(progress.sector<=progress.sectors)
sprintf(xorriso->info_text, "Writing: sector %d of %d",
progress.sector, progress.sectors);
else
sprintf(xorriso->info_text, "Writing: sector %d", progress.sector);
ret= isoburn_get_fifo_status(drive, &size, &free_bytes, &status_text);
if(ret>0 )
sprintf(xorriso->info_text+strlen(xorriso->info_text),
" [fifo %s, %2d%% fill]", status_text,
(int) (100.0-100.0*((double) free_bytes)/(double) size));
}
} else if(drive_status == BURN_DRIVE_CLOSING_SESSION ||
drive_status == BURN_DRIVE_CLOSING_TRACK)
sprintf(xorriso->info_text,
"Closing track/session. Working since %.f seconds",
current_time-start_time);
else if(drive_status == BURN_DRIVE_FORMATTING)
sprintf(xorriso->info_text, "Formatting. Working since %.f seconds",
current_time-start_time);
else
sprintf(xorriso->info_text,
"Thank you for being patient since %.f seconds",
current_time-start_time);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0);
for(i= 0; i<10; i++) {
Xorriso_process_msg_queues(xorriso, 0);
if(aborting<=0)
aborting= Xorriso_check_burn_abort(xorriso, 0);
usleep(100000);
}
}
return(1);
}
int Xorriso__read_pacifier(IsoImage *image, IsoFileSource *filesource)
{
struct XorrisO *xorriso;
xorriso= (struct XorrisO *) iso_image_get_attached_data(image);
if(xorriso==NULL)
return(1);
xorriso->pacifier_count++;
if(xorriso->pacifier_count%10)
return(1);
Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0,
"", 0);
return(1);
}
int Xorriso_get_volume(struct XorrisO *xorriso, IsoImage **volume,
int flag)
{
if(xorriso->in_volset_handle==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"No ISO image present.");
if(xorriso->indev[0]==0 && xorriso->outdev[0]==0)
sprintf(xorriso->info_text+strlen(xorriso->info_text),
" No -dev, -indev, or -outdev selected.");
else
sprintf(xorriso->info_text+strlen(xorriso->info_text),
" Possible program error with drive '%s'.", xorriso->indev);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
*volume= (IsoImage *) xorriso->in_volset_handle;
return(*volume != NULL);
}
/* @param flag bit0=do not complain about non existent node */
int Xorriso_node_from_path(struct XorrisO *xorriso, IsoImage *volume,
char *path, IsoNode **node, int flag)
{
int ret;
char sfe[5*SfileadrL], *path_pt;
path_pt= path;
if(path[0]==0)
path_pt= "/";
*node= NULL;
ret= iso_tree_path_to_node(volume, path_pt, node);
Xorriso_process_msg_queues(xorriso,0);
if(ret<=0) {
if(!(flag&1)) {
sprintf(xorriso->info_text, "Cannot find path %s in loaded ISO image",
Text_shellsafe(path_pt, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
}
return(0);
}
return(1);
}
/* @param eff_path returns resulting effective path.
Must provide at least SfileadrL bytes of storage.
@param flag bit0= do not produce problem events (unless faulty path format)
bit1= work purely literally, do not use libisofs
bit2= (with bit1) this is an address in the disk world
@return -1 = faulty path format, 0 = not found ,
1 = found simple node , 2 = found directory
*/
int Xorriso_normalize_img_path(struct XorrisO *xorriso, char *wd,
char *img_path, char eff_path[], int flag)
{
int ret, is_dir= 0, done= 0;
IsoImage *volume;
IsoDir *dir= NULL;
IsoNode *node= NULL;
char path[SfileadrL], *apt, *npt, sfe[5*SfileadrL], *cpt;
eff_path[0]= 0;
if(img_path[0]==0)
return(2); /* root directory */
if(!(flag&2)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
}
apt= npt= path;
if(img_path[0]!='/') {
strcpy(path, wd);
ret= Sfile_add_to_path(path, img_path, 0);
if(ret<=0)
goto much_too_long;
} else
if(Sfile_str(path, img_path, 0)<=0)
return(-1);
if(path[0]!='/') {
sprintf(xorriso->info_text,
"Internal error: Unresolvable relative addressing in iso_rr_path '%s'",
img_path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FATAL", 0);
return(-1);
} else if(path[1]==0)
return(2); /* root directory */
for(npt= apt; !done; apt= npt+1) {
npt= strchr(apt, '/');
if(npt==NULL) {
npt= apt+strlen(apt);
done= 1;
} else
*npt= 0;
if(*apt==0) {
*apt= '/';
apt++;
if(done)
break;
continue;
}
if(strcmp(apt,".")==0) {
is_dir= 1;
continue;
}
if(strcmp(apt,"..")==0) {
if(!(flag&2)) {
node= (IsoNode *) dir;
if(node==NULL) {
bonked_root:;
sprintf(xorriso->info_text,
"Relative addressing in path exceeds root directory: %s",
Text_shellsafe(img_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(-1);
}
dir= iso_node_get_parent(node);
}
/* truncate eff_path */;
cpt= strrchr(eff_path, '/');
if(cpt==NULL) /* ??? if not flag&2 then this is a bug */
goto bonked_root;
*cpt= 0;
is_dir= 1;
continue;
}
ret= Sfile_add_to_path(eff_path, apt, 0);
if(ret<=0) {
much_too_long:;
sprintf(xorriso->info_text, "Effective path gets much too long (%d)",
(int) (strlen(eff_path)+strlen(apt)+1));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(-1);
}
if(!(flag&2)) {
dir= (IsoDir *) node;
ret= Xorriso_node_from_path(xorriso, volume, eff_path, &node, flag&1);
if(ret<=0)
return(0);
if(dir==NULL) /* could be false with "/dir/.." */
dir= iso_node_get_parent(node);
is_dir= LIBISO_ISDIR(node);
}
}
return(1+!!is_dir);
}
int Xorriso_get_node_by_path(struct XorrisO *xorriso,
char *in_path, char *eff_path,
IsoNode **node, int flag)
{
int ret;
char path[SfileadrL];
IsoImage *volume;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, in_path, path, 0);
if(ret<=0)
return(ret);
if(eff_path!=NULL)
strcpy(eff_path, path);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
ret= Xorriso_node_from_path(xorriso, volume, path, node, 0);
if(ret<=0)
return(0);
return(1);
}
int Xorriso_transfer_properties(struct XorrisO *xorriso, struct stat *stbuf,
IsoNode *node, int flag)
{
iso_node_set_permissions(node, stbuf->st_mode & 07777);
iso_node_set_uid(node, stbuf->st_uid);
iso_node_set_gid(node, stbuf->st_gid);
iso_node_set_atime(node, stbuf->st_atime);
iso_node_set_mtime(node, stbuf->st_mtime);
iso_node_set_ctime(node, stbuf->st_ctime);
return(1);
}
/* @param flag bit0= recursion is active
bit1= do not report added files
*/
int Xorriso_add_tree(struct XorrisO *xorriso, IsoDir *dir,
char *img_dir_path, char *disk_dir_path,
struct LinkiteM *link_stack, int flag)
{
IsoImage *volume;
IsoNode *node;
IsoSymlink *iso_symlink;
int ret, target_is_dir, source_is_dir, source_is_link, fret, was_failure= 0;
int do_not_dive;
struct DirseQ *dirseq= NULL;
char *name, *img_name, *srcpt, *stbuf_src= "";
struct stat stbuf, hstbuf;
dev_t dir_dev;
struct LinkiteM *own_link_stack;
#ifdef Xorriso_fat_local_meM
char sfe[5*SfileadrL], sfe2[5*SfileadrL];
char disk_path[2*SfileadrL], img_path[2*SfileadrL], link_target[SfileadrL];
#else /* Xorriso_fat_local_meM */
char *sfe= NULL, *sfe2= NULL;
char *disk_path= NULL, *img_path= NULL, *link_target= NULL;
/* Avoiding large local memory objects in order to save stack space */
sfe= malloc(5*SfileadrL);
sfe2= malloc(5*SfileadrL);
disk_path= malloc(2*SfileadrL);
img_path= malloc(2*SfileadrL);
link_target= malloc(SfileadrL);
if(sfe==NULL || sfe2==NULL || disk_path==NULL || img_path==NULL ||
link_target==NULL) {
Xorriso_no_malloc_memory(xorriso, &sfe, 0);
{ret= -1; goto ex;}
}
#endif /* ! Xorriso_fat_local_meM */
own_link_stack= link_stack;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
stbuf_src= disk_dir_path;
if(lstat(disk_dir_path, &stbuf)==-1)
goto cannot_open_dir;
dir_dev= stbuf.st_dev;
if(S_ISLNK(stbuf.st_mode)) {
if(!(xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&1))))
{ret= 2; goto ex;}
stbuf_src= disk_dir_path;
if(stat(disk_dir_path, &stbuf)==-1)
goto cannot_open_dir;
if(dir_dev != stbuf.st_dev &&
!(xorriso->do_follow_mount || (xorriso->do_follow_param && !(flag&1))))
{ret= 2; goto ex;}
}
ret= Dirseq_new(&dirseq, disk_dir_path, 1);
if(ret<0) {
sprintf(xorriso->info_text,"Failed to create source filesystem iterator");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
{ret= -1; goto ex;}
}
if(ret==0) {
cannot_open_dir:;
Xorriso_msgs_submit(xorriso, 0, disk_dir_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,"Cannot open as source directory: %s",
Text_shellsafe(disk_dir_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
if(Sfile_str(disk_path, disk_dir_path,0)<=0)
{ret= -1; goto ex;}
if(disk_path[0]==0 || disk_path[strlen(disk_path)-1]!='/')
strcat(disk_path,"/");
name= disk_path+strlen(disk_path);
if(Sfile_str(img_path, img_dir_path, 0)<=0)
{ret= -1; goto ex;}
if(img_path[0] || img_path[strlen(img_path)-1]!='/')
strcat(img_path,"/");
img_name= img_path+strlen(img_path);
while(1) { /* loop over directory content */
stbuf_src= "";
Linkitem_reset_stack(&own_link_stack, link_stack, 0);
srcpt= disk_path;
Xorriso_process_msg_queues(xorriso,0);
ret= Dirseq_next_adr(dirseq,name,0);
if(ret==0)
break;
if(ret<0) {
sprintf(xorriso->info_text,"Failed to obtain next directory entry");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
{ret= -1; goto ex;}
}
strcpy(img_name, name);
if(Xorriso_much_too_long(xorriso, strlen(img_path), 0)<=0)
{ret= 0; goto was_problem;}
if(Xorriso_much_too_long(xorriso, strlen(srcpt), 0)<=0)
{ret= 0; goto was_problem;}
stbuf_src= srcpt;
if(lstat(srcpt, &stbuf)==-1) {
cannot_lstat:;
Xorriso_msgs_submit(xorriso, 0, srcpt, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Cannot determine attributes of source file %s",
Text_shellsafe(srcpt, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
ret= 0; goto was_problem;
}
source_is_dir= 0;
source_is_link= S_ISLNK(stbuf.st_mode);
if(xorriso->do_follow_links && source_is_link) {
/* Xorriso_hop_link checks for wide link loops */
ret= Xorriso_hop_link(xorriso, srcpt, &own_link_stack, &hstbuf, 0);
if(ret<0)
goto was_problem;
if(ret==1) {
ret= Xorriso_resolve_link(xorriso, srcpt, link_target, 0);
if(ret<=0)
goto was_problem;
srcpt= link_target;
stbuf_src= srcpt;
if(lstat(srcpt, &stbuf)==-1)
goto cannot_lstat;
} else {
if(Xorriso_eval_problem_status(xorriso, 0, 1|2)<0)
{ret= 0; goto was_problem;}
}
} else if (S_ISLNK(stbuf.st_mode)) {
ret= Xorriso_resolve_link(xorriso, srcpt, link_target, 1);
if(ret<=0)
goto was_problem;
}
do_not_dive= 0;
if(S_ISDIR(stbuf.st_mode)) {
source_is_dir= 1;
if(dir_dev != stbuf.st_dev && !xorriso->do_follow_mount)
do_not_dive= 1;
#ifdef NIX
} else if(!(S_ISREG(stbuf.st_mode) || S_ISLNK(stbuf.st_mode))) {
Xorriso_msgs_submit(xorriso, 0, stbuf_src, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,"Source file %s %s non-supported file type",
Text_shellsafe(srcpt, sfe, 0),
source_is_link ? "leads to" : "is of");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto was_problem;
#endif /* NIX */
}
/* does a node exist with this name ? */
node= NULL;
ret= Xorriso_node_from_path(xorriso, volume, img_path, &node, 1);
if(ret>0) {
target_is_dir= LIBISO_ISDIR(node);
if(!(target_is_dir && source_is_dir)) {
Xorriso_process_msg_queues(xorriso,0);
/* handle overwrite situation */;
if(xorriso->do_overwrite==1 ||
(xorriso->do_overwrite==2 && !target_is_dir)) {
ret= Xorriso_rmi(xorriso, NULL, img_path, 1|8);
if(ret<=0)
goto was_problem;
if(ret==3) {
sprintf(xorriso->info_text, "User revoked adding of: %s",
Text_shellsafe(img_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= 0; goto was_problem;
}
node= NULL;
} else {
Xorriso_msgs_submit(xorriso, 0, srcpt, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"While grafting %s : file object exists and may not be overwritten by %s",
Text_shellsafe(img_path,sfe,0), Text_shellsafe(stbuf_src,sfe2,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto was_problem;
}
}
}
if(node==NULL) {
if(S_ISLNK(stbuf.st_mode)) {
/* ??? NG : A80107 : is this solved now ? */
/* <<< One should rather change libisofs so that iso_tree_add_node()
adds a disk_link as RR link, if RR is enabled */
ret= iso_tree_add_new_symlink(dir, img_name, link_target, &iso_symlink);
node= (IsoNode *) iso_symlink;
if(ret>0) {
ret= Xorriso_transfer_properties(xorriso, &stbuf, node, 0);
if(ret<=0)
goto was_problem;
} else {
Xorriso_report_iso_error(xorriso, stbuf_src, ret,
"Cannot create symbolic link", 0, "FAILURE", 1|2);
{ret= 0; goto was_problem;}
}
} else {
ret= iso_tree_add_node(volume, dir, srcpt, &node);
if(ret<0) {
Xorriso_report_iso_error(xorriso, stbuf_src, ret,
"Cannot add node to tree", 0, "FAILURE", 1|2);
goto was_problem;
}
}
}
if(node==NULL) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_msgs_submit(xorriso, 0, stbuf_src, 0, "ERRFILE", 0);
sprintf(xorriso->info_text, "Grafting failed: %s = %s",
Text_shellsafe(img_path,sfe,0), Text_shellsafe(stbuf_src,sfe2,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret=0; goto was_problem;
}
xorriso->pacifier_count++;
if((xorriso->pacifier_count%100)==0)
Xorriso_pacifier_callback(xorriso, "files added", xorriso->pacifier_count,
xorriso->pacifier_total, "", 0);
xorriso->volset_change_pending= 1;
if(source_is_dir) {
if(do_not_dive) {
sprintf(xorriso->info_text, "Did not follow mount point : %s",
Text_shellsafe(disk_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
} else {
ret= Xorriso_add_tree(xorriso, (IsoDir *) node,
img_path, disk_path, own_link_stack, 1|(flag&2));
}
if(ret<=0)
goto was_problem;
}
continue; /* regular bottom of loop */
was_problem:;
was_failure= 1;
fret= Xorriso_eval_problem_status(xorriso, ret, 1|2);
if(fret<0)
goto ex;
}
ret= 1;
ex:
#ifndef Xorriso_fat_local_meM
if(sfe!=NULL)
free(sfe);
if(sfe2!=NULL)
free(sfe2);
if(disk_path!=NULL)
free(disk_path);
if(img_path!=NULL)
free(img_path);
if(link_target!=NULL)
free(link_target);
#endif /* ! Xorriso_fat_local_meM */
Xorriso_process_msg_queues(xorriso,0);
Linkitem_reset_stack(&own_link_stack, link_stack, 0);
Dirseq_destroy(&dirseq, 0);
if(ret<=0)
return(ret);
return(!was_failure);
}
int Xorriso_copy_implict_properties(struct XorrisO *xorriso, IsoDir *dir,
char *full_img_path, char *img_path, char *full_disk_path, int flag)
{
int ret, nfic, nic, nfdc, d, i;
char nfi[SfileadrL], ni[SfileadrL], nfd[SfileadrL], *cpt;
char sfe[5*SfileadrL];
struct stat stbuf;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, full_img_path, nfi,
1|2);
if(ret<=0)
return(ret);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, img_path, ni, 1|2);
if(ret<=0)
return(ret);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, full_disk_path, nfd,
1|2|4);
if(ret<=0)
return(ret);
nfic= Sfile_count_components(nfi, 0);
nic= Sfile_count_components(ni, 0);
nfdc= Sfile_count_components(nfd, 0);
d= nfic-nic;
if(d<0)
return(-1);
if(d>nfdc)
return(0);
for(i= 0; i<d; i++) {
cpt= strrchr(nfd, '/');
if(cpt==NULL)
return(-1); /* should not happen */
*cpt= 0;
}
if(nfd[0]==0)
strcpy(nfd, "/");
if(stat(nfd, &stbuf)==-1)
return(0);
Xorriso_transfer_properties(xorriso, &stbuf, (IsoNode *) dir, 0);
sprintf(xorriso->info_text,
"Copied properties for %s", Text_shellsafe(ni, sfe, 0));
sprintf(xorriso->info_text+strlen(xorriso->info_text),
" from %s", Text_shellsafe(nfd, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
return(1);
}
/* @param bit0= copy link target properties rather than link properties
*/
int Xorriso_copy_properties(struct XorrisO *xorriso,
char *disk_path, char *img_path, int flag)
{
int ret;
IsoNode *node;
struct stat stbuf;
ret= Xorriso_get_node_by_path(xorriso, img_path, NULL, &node, 0);
if(ret<=0)
return(ret);
if(lstat(disk_path, &stbuf)==-1)
return(0);
Xorriso_transfer_properties(xorriso, &stbuf, node, 0);
xorriso->volset_change_pending= 1;
return(1);
}
/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
Set to NULL if calling this function from outside ISO world
@param flag bit0= mkdir: graft in as empty directory, not as copy from disk
bit1= do not report added files
bit2= -follow: this is not a command parameter
@return <=0 = error , 1 = added simple node , 2 = added directory
*/
int Xorriso_graft_in(struct XorrisO *xorriso, void *boss_iter,
char *disk_path, char *img_path, int flag)
{
IsoImage *volume;
char path[SfileadrL], *apt, *npt, *cpt, sfe[5*SfileadrL], sfe2[5*SfileadrL];
char *disk_path_pt, resolved_disk_path[SfileadrL];
IsoDir *dir, *hdir;
IsoNode *node;
int done= 0, is_dir= 0, l, ret, target_is_dir, source_is_dir, resolve_link= 0;
struct stat stbuf;
for(cpt= img_path; 1; cpt++) {
/*
if(cpt[0]!='/')
break;
*/
cpt= strstr(cpt,"/.");
if(cpt==NULL)
break;
if(cpt[2]=='.') {
if(cpt[3]=='/' || cpt[3]==0)
break;
} else if(cpt[2]=='/' || cpt[2]==0)
break;
}
if(cpt!=NULL) {
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Unsupported relative addressing in iso_rr_path %s (disk: %s)",
Text_shellsafe(img_path, sfe, 0), Text_shellsafe(disk_path, sfe2, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
return(0);
}
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
strncpy(path, img_path, sizeof(path)-1);
path[sizeof(path)-1]= 0;
apt= npt= path;
if(!(flag&1)) {
ret= lstat(disk_path, &stbuf);
if(ret!=-1) {
if(S_ISDIR(stbuf.st_mode))
is_dir= 1;
else if((stbuf.st_mode&S_IFMT)==S_IFLNK &&
(xorriso->do_follow_links ||
(xorriso->do_follow_param && !(flag&4)))) {
resolve_link= 1;
ret= stat(disk_path, &stbuf);
if(ret!=-1) {
if(S_ISDIR(stbuf.st_mode))
is_dir= 1;
}
}
}
if(ret == -1) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Cannot determine attributes of source file %s",
Text_shellsafe(disk_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
return(0);
}
if(S_ISDIR(stbuf.st_mode)) {
is_dir= 1;
#ifdef NIX
} else if(!(S_ISREG(stbuf.st_mode) || S_ISLNK(stbuf.st_mode))) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Source file '%s' is of non-supported file type", disk_path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
#endif /* NIX */
} else {
l= strlen(img_path);
if(l>0)
if(img_path[l-1]=='/')
l= 0;
if(l==0) {
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Source '%s' is not a directory. Target '%s' would be.",
Text_shellsafe(disk_path, sfe, 0), Text_shellsafe(img_path, sfe2, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
}
}
dir= iso_image_get_root(volume);
if(dir==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"While grafting '%s' : no root node available", img_path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(0);
}
for(npt= apt; !done; apt= npt+1) {
npt= strchr(apt, '/');
if(npt==NULL) {
npt= apt+strlen(apt);
done= 1;
} else
*npt= 0;
if(*apt==0) {
*apt= '/';
apt++;
if(done)
goto attach_source;
continue;
}
source_is_dir= (is_dir || (flag&1) || !done);
ret= Xorriso_node_from_path(xorriso, volume, path, &node, 1);
if(ret>0) {
target_is_dir= LIBISO_ISDIR(node);
if(!(target_is_dir && source_is_dir)) {
Xorriso_process_msg_queues(xorriso,0);
/* handle overwrite situation */;
if(xorriso->do_overwrite==1 ||
(xorriso->do_overwrite==2 && !target_is_dir)) {
ret= Xorriso_rmi(xorriso, boss_iter, path, 1|8);
if(ret<=0)
return(ret);
if(ret==3) {
sprintf(xorriso->info_text, "User revoked adding of: %s",
Text_shellsafe(disk_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(0);
}
node= NULL;
goto handle_path_node;
}
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"While grafting '%s' : '%s' exists and may not be overwritten",
img_path, path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
dir= (IsoDir *) node;
}
handle_path_node:;
if(node==NULL && source_is_dir) { /* make a directory */
ret= iso_tree_add_new_dir(dir, apt, &hdir);
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
Xorriso_report_iso_error(xorriso, img_path, ret,
"Cannot create directory", 0, "FAILURE", 1);
sprintf(xorriso->info_text,
"While grafting '%s' : could not insert '%s'", img_path, path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
dir= hdir;
xorriso->volset_change_pending= 1;
iso_node_set_ctime((IsoNode *) dir, time(NULL));
iso_node_set_uid((IsoNode *) dir, geteuid());
iso_node_set_gid((IsoNode *) dir, getegid());
if(!done)
Xorriso_copy_implict_properties(xorriso, dir, img_path, path, disk_path,
0);
}
if(done) {
attach_source:;
xorriso->pacifier_count++;
if(xorriso->pacifier_count%100 && !(flag&2))
Xorriso_pacifier_callback(xorriso, "files added",
xorriso->pacifier_count,
xorriso->pacifier_total, "", 0);
if(flag&1) {
/* directory node was created above */;
} else if(is_dir) {
Xorriso_transfer_properties(xorriso, &stbuf, (IsoNode *) dir, 0);
ret= Xorriso_add_tree(xorriso, dir, img_path, disk_path, NULL, flag&2);
if(ret<=0)
return(ret);
} else {
if(resolve_link) {
ret= Xorriso_resolve_link(xorriso, disk_path, resolved_disk_path, 0);
if(ret<=0)
return(ret);
disk_path_pt= resolved_disk_path;
} else
disk_path_pt= disk_path;
ret= iso_tree_add_node(volume, dir, disk_path_pt, &node);
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
Xorriso_report_iso_error(xorriso, img_path, ret, "Cannot create node",
0, "FAILURE", 1);
sprintf(xorriso->info_text, "Grafting failed: %s = %s",
Text_shellsafe(img_path,sfe,0), Text_shellsafe(disk_path,sfe2,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
xorriso->volset_change_pending= 1;
iso_node_set_name(node, apt);
}
} else
*npt= '/';
}
Xorriso_process_msg_queues(xorriso,0);
return(1+!!is_dir);
}
int Xorriso_process_msg_queues(struct XorrisO *xorriso, int flag)
{
int ret, error_code= 0, os_errno= 0, count= 0, pass, imgid, tunneled;
char severity[80];
if(!xorriso->libs_are_started)
return(1);
for(pass= 0; pass< 2; pass++) {
while(1) {
tunneled= 0;
if(pass==0)
ret= iso_obtain_msgs("ALL", &error_code, &imgid,
xorriso->info_text, severity);
else {
ret= burn_msgs_obtain("ALL", &error_code, xorriso->info_text, &os_errno,
severity);
if((error_code>=0x00030000 && error_code<0x00040000) ||
(error_code>=0x00050000 && error_code<0x00060000))
tunneled= -1; /* "libisofs:" */
else if(error_code>=0x00060000 && error_code<0x00070000)
tunneled= 1; /* "libisoburn:" */
}
if(ret<=0)
break;
/* <<< tunneled MISHAP from libisoburn through libburn
or well known error codes of MISHAP events
With libburn-0.4.4 this is not necessary */
if(error_code==0x5ff73 || error_code==0x3ff73 ||
error_code==0x3feb9 || error_code==0x3feb2)
strcpy(severity, "MISHAP");
else if(error_code==0x51001)
strcpy(severity, "ERRFILE");
Xorriso_msgs_submit(xorriso, error_code, xorriso->info_text, os_errno,
severity, ((pass+tunneled)+1)<<2);
count++;
}
}
if(xorriso->library_msg_direct_print && count>0) {
sprintf(xorriso->info_text," (%d library messages repeated by xorriso)\n",
count);
Xorriso_info(xorriso, 0);
}
return(1);
}
/* @param flag bit0=short report form
bit1=report about output drive
*/
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;
int last_track_start= 0, last_track_size= -1, num_data= 0, is_data= 0;
int is_inout_drive= 0, drive_role;
char profile_name[80],*respt,*devadr;
struct burn_disc *disc= NULL;
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_toc_entry toc_entry;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
enum burn_disc_status s;
char mem_text[80];
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to print Table Of Content", flag&2);
if(ret<=0)
return(0);
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_result(xorriso,0);
sprintf(respt, "Drive type : vendor '%s' product '%s' revision '%s'\n",
dinfo[0].vendor, dinfo[0].product, dinfo[0].revision);
if(!(flag&1))
Xorriso_result(xorriso,0);
sprintf(respt, "Media current: ");
ret= burn_disc_get_profile(drive, &profile_no, profile_name);
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");
Xorriso_result(xorriso,0);
sprintf(respt, "Media status : ");
s= isoburn_disc_get_status(drive);
if (s == BURN_DISC_FULL) {
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_result(xorriso,0);
if(s != BURN_DISC_FULL && s != BURN_DISC_APPENDABLE)
return(1);
if(xorriso->request_to_abort)
return(1);
disc= burn_drive_get_disc(drive);
if (disc==NULL) {
Xorriso_process_msg_queues(xorriso,0);
#define Xorriso_with_isoburn_get_min_start_bytE 1
#ifdef Xorriso_with_isoburn_get_min_start_bytE
{ off_t start_byte= 0;
ret= isoburn_get_min_start_byte(drive, &start_byte, 0);
nwa= start_byte / 2048;
}
#else
ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
#endif
if(ret<=0) {
Xorriso_process_msg_queues(xorriso,0);
if(flag&1)
return(0);
sprintf(xorriso->info_text, "Cannot obtain Table Of Content");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
return(0);
}
/* fabricate TOC */
sprintf(respt, "Media content: session %2d ", 1);
sprintf(respt+strlen(respt), "track %2d %s lba: %9d\n", 1, "data ", 0);
if(!(flag&1))
Xorriso_result(xorriso,0);
last_track_start= lba;
sprintf(respt, "Media content: session %2d ", 1);
sprintf(respt+strlen(respt), "leadout lba: %9d\n", nwa);
if(!(flag&1))
Xorriso_result(xorriso,0);
num_data= last_track_size= nwa;
num_sessions= 1;
} else {
sessions= burn_disc_get_sessions(disc, &num_sessions);
for (session_no= 0; session_no<num_sessions && !(xorriso->request_to_abort);
session_no++) {
tracks = burn_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;
burn_track_get_entry(tracks[track_no], &toc_entry);
if (toc_entry.extensions_valid & 1) {
/* DVD extension valid */
lba= toc_entry.start_lba;
} else {
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe);
}
sprintf(respt, "Media content: session %2d ", session_no+1);
sprintf(respt+strlen(respt), "track %2d %s lba: %9d\n",
track_count, ((toc_entry.control&7)<4?"audio":"data "), lba);
if(!(flag&1))
Xorriso_result(xorriso,0);
last_track_start= lba;
if((toc_entry.control&7)>=4) /* data track */
is_data= 1;
}
burn_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);
}
sprintf(respt, "Media content: session %2d ", session_no+1);
sprintf(respt+strlen(respt), "leadout lba: %9d\n", lba);
if(!(flag&1))
Xorriso_result(xorriso,0);
last_track_size= lba - last_track_start;
if(is_data)
num_data+= last_track_size;
}
}
if(xorriso->request_to_abort)
return(1);
Sfile_scale(((double) num_data) * 2048.0, mem_text,5,1e4,1);
sprintf(respt, "Media summary: %d session%s, %d data blocks, %s\n",
num_sessions, (num_sessions==1 ? "" : "s"), num_data, mem_text);
Xorriso_result(xorriso,0);
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_result(xorriso,0);
}
}
if (disc!=NULL)
burn_disc_free(disc);
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_show_devices(struct XorrisO *xorriso, int flag)
{
char adr[BURN_DRIVE_ADR_LEN];
int i;
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(xorriso,0);
burn_drive_clear_whitelist();
while(!burn_drive_scan(&drive_list, &drive_count)) {
Xorriso_process_msg_queues(xorriso,0);
usleep(100000);
}
Xorriso_process_msg_queues(xorriso,0);
if(drive_count <= 0) {
/* >>> was a drive_list created at all ? */
/* >>> must it be freed ? */
sprintf(xorriso->info_text, "No drives found");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
return(0);
}
sprintf(xorriso->info_text, "Full drive scan done\n");
Xorriso_info(xorriso,0);
respt= xorriso->result_line;
for(i= 0; i < drive_count && !(xorriso->request_to_abort); i++) {
if(burn_drive_get_adr(&(drive_list[i]), adr)<=0)
strcpy(adr, "-get_adr_failed-");
Xorriso_process_msg_queues(xorriso,0);
if(stat(adr,&stbuf)==-1) {
sprintf(perms,"errno=%d",errno);
} else {
strcpy(perms,"------");
if(stbuf.st_mode&S_IRUSR) perms[0]= 'r';
if(stbuf.st_mode&S_IWUSR) perms[1]= 'w';
if(stbuf.st_mode&S_IRGRP) perms[2]= 'r';
if(stbuf.st_mode&S_IWGRP) perms[3]= 'w';
if(stbuf.st_mode&S_IROTH) perms[4]= 'r';
if(stbuf.st_mode&S_IWOTH) perms[5]= 'w';
}
sprintf(respt, "%d -dev '%s' %s : '%-8.8s' '%s' \n",
i, adr, perms, drive_list[i].vendor, drive_list[i].product);
Xorriso_result(xorriso,0);
}
burn_drive_info_free(drive_list);
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_tell_media_space(struct XorrisO *xorriso,
int *media_space, int *free_space, int flag)
{
int ret;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
struct burn_write_opts *burn_options;
(*free_space)= (*media_space)= 0;
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to -tell_media_space", 2);
if(ret<=0)
return(0);
ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
if(ret<=0)
return(-1);
(*free_space)= (*media_space)=
isoburn_disc_available_space(drive, burn_options) / (off_t) 2048;
burn_write_opts_free(burn_options);
if(xorriso->volset_change_pending) {
ret= Xorriso_write_session(xorriso, 1);
if(ret>0)
(*free_space)-= ret;
}
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
/* @param flag bit0=fast , bit1=deformat
@return 0=failure, did not touch media , -1=failure, altered media
1=success, altered media , 2=success, did not touch media
*/
int Xorriso_blank_media(struct XorrisO *xorriso, int flag)
{
int ret, do_deformat= 0;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
enum burn_disc_status disc_state;
struct burn_progress p;
double percent = 1.0;
int current_profile;
char current_profile_name[80];
char mode_names[4][80]= {"all", "fast", "deformat", "deformat_quickest"};
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to -blank", 2);
if(ret<=0)
return(0);
burn_disc_get_profile(drive, &current_profile, current_profile_name);
/* >>> */;
disc_state = isoburn_disc_get_status(drive);
if(current_profile == 0x13) { /* overwriteable DVD-RW */
/* Depending on flag bit1 formatted DVD-RW will get blanked to sequential
state or pseudo blanked by invalidating an eventual ISO image. */
if(flag&2)
do_deformat= 1;
} else if(current_profile == 0x14) { /* sequential DVD-RW */
if((flag&1) && !(flag&2)) {
sprintf(xorriso->info_text,
"-blank: DVD-RW present. Mode 'fast' defaulted to mode 'all'.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
sprintf(xorriso->info_text,
"Mode 'deformat_quickest' produces single-session-only media.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
flag&= ~1;
}
} else if(disc_state == BURN_DISC_BLANK) {
sprintf(xorriso->info_text,"Blank media detected. Will leave it untouched");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return 2;
} else if(disc_state==BURN_DISC_FULL || disc_state==BURN_DISC_APPENDABLE) {
;
} else if(disc_state == BURN_DISC_EMPTY) {
sprintf(xorriso->info_text,"No media detected in drive");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return 0;
} else {
sprintf(xorriso->info_text, "Unsuitable drive and media state");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return 0;
}
if(!isoburn_disc_erasable(drive)) {
sprintf(xorriso->info_text, "Media is not of erasable type");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return 0;
}
if(xorriso->do_dummy) {
sprintf(xorriso->info_text,
"-dummy mode prevents blanking of media in mode '%s'.",
mode_names[flag&3]);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(1);
}
sprintf(xorriso->info_text, "Beginning to blank media in mode '%s'.\n",
mode_names[flag&3]);
Xorriso_info(xorriso,0);
if(do_deformat)
burn_disc_erase(drive, (flag&1));
else
isoburn_disc_erase(drive, (flag&1));
usleep(1000000);
while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
percent = 1.0 + ((double) p.sector+1.0) / ((double) p.sectors) * 98.0;
sprintf(xorriso->info_text, "Blanking ( %.1f%% done )", percent);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0);
usleep(1000000);
}
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text, "Blanking done\n");
Xorriso_info(xorriso,0);
return(1);
}
/* @return 0=failure, did not touch media , -1=failure, altered media
1=success, altered media , 2=success, did not touch media
*/
int Xorriso_format_media(struct XorrisO *xorriso, int flag)
{
int ret, mode_flag= 0;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
int current_profile;
char current_profile_name[80];
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to -format", 2);
if(ret<=0)
return(0);
burn_disc_get_profile(drive, &current_profile, current_profile_name);
if(current_profile == 0x14) {
; /* ok DVD-RW sequential */
} else if(current_profile == 0x1a) {
mode_flag= 2;
} else {
sprintf(xorriso->info_text,
"Can only -format DVD+RW and sequential DVD-RW");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
sprintf(xorriso->info_text,"Media current: %s (%4.4xh)",
current_profile_name, current_profile);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return 0;
}
if(xorriso->do_dummy) {
sprintf(xorriso->info_text, "-dummy mode prevents formatting of media.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(1);
}
sprintf(xorriso->info_text, "Beginning to format media.\n");
Xorriso_info(xorriso, 0);
burn_disc_format(drive, (off_t) 0, mode_flag);
ret= Xorriso_pacifier_loop(xorriso, drive, 0);
if(ret<=0)
return(ret);
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text, "Formatting done\n");
Xorriso_info(xorriso,0);
return(1);
}
int Xorriso_cannot_create_iter(struct XorrisO *xorriso, int iso_error,int flag)
{
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", iso_error, "Cannot create iter", 0,
"FATAL", 1);
sprintf(xorriso->info_text, "Cannot create IsoDirIter object");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(1);
}
/* @param boss_iter If not NULL then this is an iterator suitable for
iso_dir_iter_remove() which is then to be used instead
of iso_node_remove().
@param flag bit0= remove whole sub tree: rm -r
bit1= remove empty directory: rmdir
bit2= recursion: do not reassure in mode 2 "tree"
bit3= this is for overwriting and not for plain removal
bit4= count deleted files in xorriso->pacifier_count
@return <=0 = error
1 = removed simple node
2 = removed directory or tree
3 = did not remove on user revocation
*/
int Xorriso_rmi(struct XorrisO *xorriso, void *boss_iter,
char *path, int flag)
{
int ret, is_dir= 0, pl, not_removed= 0, fret;
IsoNode *victim_node, *node;
IsoDir *boss_node, *root_dir;
IsoDirIter *iter= NULL;
IsoImage *volume;
char *sub_name, *name;
#ifdef Xorriso_fat_local_meM
char sfe[5*SfileadrL], sub_path[2*SfileadrL];
#else
char *sfe= NULL, *sub_path= NULL;
/* Avoiding large local memory objects in order to save stack space */
sfe= malloc(5*SfileadrL);
sub_path= malloc(2*SfileadrL);
if(sfe==NULL || sub_path==NULL) {
Xorriso_no_malloc_memory(xorriso, &sfe, 0);
{ret= -1; goto ex;}
}
#endif /* ! Xorriso_fat_local_meM */
#ifndef Libisofs_iso_dir_iter_sufficienT
/* Ticket 127: A80301 - A80302
I do not not deem IsoDirIter safe for node list manipulations.
The parameter boss_iter once was intended to allow such but
has now been downgraded to a mere check for eventual programming bugs.
*/
if(boss_iter!=NULL) {
sprintf(xorriso->info_text,
"Program error: Xorriso_rmi() was requested to delete iterated node %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
ret= -1; goto ex;
}
#endif /* Libisofs_iso_dir_iter_sufficienT */
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
if(Xorriso_much_too_long(xorriso, strlen(path), 0)<=0)
{ret= 0; goto ex;}
ret= Xorriso_node_from_path(xorriso, volume, path, &victim_node, 0);
if(ret<=0)
goto ex;
root_dir= iso_image_get_root(volume);
if(((void *) root_dir) == ((void *) victim_node)) {
sprintf(xorriso->info_text, "May not delete root directory");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
if(LIBISO_ISDIR(victim_node))
is_dir= 1;
if(!is_dir) {
if(flag&2) { /* rmdir */
sprintf(xorriso->info_text, "%s in loaded ISO image is not a directory",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
} else {
if(flag&1) { /* rm -r */
if(xorriso->do_reassure==1 && !xorriso->request_not_to_ask) {
/* Iterate over subordinates and delete them */
ret= iso_dir_get_children((IsoDir *) victim_node, &iter);
Xorriso_process_msg_queues(xorriso,0);
if(ret<0) {
cannot_create_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
ret= -1; goto ex;
}
pl= strlen(path);
strcpy(sub_path, path);
if(pl==0 || sub_path[pl-1]!='/') {
sub_path[pl++]= '/';
sub_path[pl]= 0;
}
sub_name= sub_path+pl;
while(iso_dir_iter_next(iter, &node) == 1
&& !xorriso->request_to_abort) {
name= (char *) iso_node_get_name(node);
if(Xorriso_much_too_long(xorriso, pl+1+strlen(name), 0)<=0)
{ret= 0; goto rm_r_problem_handler;}
strcpy(sub_name, name);
ret= Xorriso_rmi(xorriso, iter, sub_path, (flag&(1|2|8|16))|4);
if(ret==3 || ret<=0 || xorriso->request_to_abort) {
rm_r_problem_handler:;
not_removed= 1;
fret= Xorriso_eval_problem_status(xorriso, ret, 1|2);
if(fret<0)
goto dir_not_removed;
}
}
if(not_removed) {
dir_not_removed:;
sprintf(xorriso->info_text, "Directory not removed: %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
if(ret>0)
ret= 3;
goto ex;
}
}
} else {
if(!(flag&2)) { /* not rmdir */
sprintf(xorriso->info_text, "%s in loaded ISO image is a directory",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
ret= iso_dir_get_children((IsoDir *) victim_node, &iter);
Xorriso_process_msg_queues(xorriso,0);
if(ret<0)
goto cannot_create_iter;
if(ret>0) {
if(iso_dir_iter_next(iter, &node) == 1) {
sprintf(xorriso->info_text,
"Directory not empty on attempt to delete: %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
}
}
}
if(xorriso->request_to_abort)
{ret= 3; goto ex;}
boss_node= iso_node_get_parent(victim_node);
Xorriso_process_msg_queues(xorriso,0);
if(boss_node==NULL) {
sprintf(xorriso->info_text,
"Cannot find parent node of %s in loaded ISO image",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
while((xorriso->do_reassure==1 || (xorriso->do_reassure==2 && !(flag&4)))
&& !xorriso->request_not_to_ask) {
/* ls -ld */
Xorriso_ls_filev(xorriso, xorriso->wdi, 1, &path, (off_t) 0, 1|2|8);
if(is_dir) /* du -s */
Xorriso_ls_filev(xorriso, xorriso->wdi, 1, &path, (off_t) 0, 2|4);
if(flag&8)
sprintf(xorriso->info_text,
"File exists. Remove ? n= keep old, y= remove, x= abort, @= stop asking\n");
else
sprintf(xorriso->info_text,
"Remove above file ? n= keep it, y= remove it, x= abort, @= stop asking\n");
Xorriso_info(xorriso, 4);
ret= Xorriso_request_confirmation(xorriso, 1|2|4|16);
if(ret<=0)
goto ex;
if(xorriso->request_to_abort) {
sprintf(xorriso->info_text,
"Removal operation aborted by user before file: %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= 3; goto ex;
}
if(ret==3)
continue;
if(ret==6) /* yes */
break;
if(ret==4) { /* yes, do not ask again */
xorriso->request_not_to_ask= 1;
break;
}
if(ret==1) { /* no */
sprintf(xorriso->info_text, "Kept in existing state: %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= 3; goto ex;
}
}
#ifdef Libisofs_iso_dir_iter_sufficienT
if(boss_iter!=NULL) {
ret= iso_dir_iter_remove((IsoDirIter *) boss_iter);
if(ret<0)
ret= -1;
} else
ret= iso_node_remove(victim_node);
#else /* ! Libisofs_iso_dir_iter_sufficienT */
ret= iso_node_remove(victim_node);
#endif /* Libisofs_iso_dir_iter_sufficienT */
Xorriso_process_msg_queues(xorriso,0);
if(ret<0) {
Xorriso_report_iso_error(xorriso, path, ret, "Cannot remove node", 0,
"FATAL", 1);
sprintf(xorriso->info_text,
"Internal failure to remove %s from loaded ISO image",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
ret= -1; goto ex;
}
if(flag&16)
xorriso->pacifier_count++;
xorriso->volset_change_pending= 1;
ret= 1+!!is_dir;
ex:;
#ifndef Xorriso_fat_local_meM
if(sfe!=NULL)
free(sfe);
if(sub_path!=NULL)
free(sub_path);
#endif /* ! Xorriso_fat_local_meM */
if(iter!=NULL)
iso_dir_iter_free(iter);
return(ret);
}
int Xorriso__node_name_cmp(const void *node1, const void *node2)
{
char *name1, *name2;
name1= (char *) iso_node_get_name(*((IsoNode **) node1));
name2= (char *) iso_node_get_name(*((IsoNode **) node2));
return(strcmp(name1,name2));
}
/* @param flag bit0= only accept directory nodes
bit1= do not report memory usage as DEBUG
bit2= do not apply search pattern but accept any node
*/
int Xorriso_sorted_node_array(struct XorrisO *xorriso,
IsoDir *dir_node,
int *nodec, IsoNode ***node_array,
off_t boss_mem, int flag)
{
int i, ret, failed_at;
char *npt;
IsoDirIter *iter= NULL;
IsoNode *node;
off_t mem;
mem= ((*nodec)+1)*sizeof(IsoNode *);
ret= Xorriso_check_temp_mem_limit(xorriso, mem+boss_mem, flag&2);
if(ret<=0)
return(ret);
*node_array= calloc(sizeof(IsoNode *), (*nodec)+1);
if(*node_array==NULL) {
sprintf(xorriso->info_text,
"Cannot allocate memory for %d directory entries", *nodec);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0) {
Xorriso_cannot_create_iter(xorriso, ret, 0);
return(-1);
}
for(i= 0; iso_dir_iter_next(iter, &node) == 1 && i<*nodec; ) {
npt= (char *) iso_node_get_name(node);
if(!(flag&4)) {
ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
if(ret)
continue; /* no match */
}
if(flag&1)
if(!LIBISO_ISDIR(node))
continue;
(*node_array)[i++]= node;
}
iso_dir_iter_free(iter);
*nodec= i;
if(*nodec<=0)
return(1);
qsort(*node_array, *nodec, sizeof(IsoNode *), Xorriso__node_name_cmp);
return(1);
}
/* @param flag bit0= do not only sum up sizes but also print subdirs
*/
int Xorriso_show_du_subs(struct XorrisO *xorriso, IsoDir *dir_node,
char *abs_path, char *rel_path, off_t *size,
off_t boss_mem, int flag)
{
int i, ret, no_sort= 0, filec= 0, l;
IsoDirIter *iter= NULL;
IsoNode *node, **node_array= NULL;
char *name;
off_t sub_size, report_size, mem= 0;
#ifdef Xorriso_fat_local_meM
char path[SfileadrL], show_path[SfileadrL], sfe[5*SfileadrL];
#else /* Xorriso_fat_local_meM */
char *path= NULL, *show_path= NULL, *sfe= NULL;
sfe= malloc(5*SfileadrL);
path= malloc(SfileadrL);
show_path= malloc(SfileadrL);
if(path==NULL || show_path==NULL || sfe==NULL) {
Xorriso_no_malloc_memory(xorriso, &sfe, 0);
{ret= -1; goto ex;}
}
#endif /* ! Xorriso_fat_local_meM */
*size= 0;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0) {
cannot_create_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
{ret= -1; goto ex;}
}
for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
sub_size= 0;
name= (char *) iso_node_get_name(node);
strcpy(show_path, rel_path);
if(Sfile_add_to_path(show_path, name, 0)<=0)
goto much_too_long;
if(LIBISO_ISDIR(node)) {
strcpy(path, abs_path);
if(Sfile_add_to_path(path, name, 0)<=0) {
much_too_long:;
Xorriso_much_too_long(xorriso, strlen(path)+strlen(name)+1, 2);
{ret= -1; goto ex;}
}
filec++;
l= strlen(rel_path)+1;
mem+= l;
if(l % sizeof(char *))
mem+= sizeof(char *)-(l % sizeof(char *));
if(flag&1) /* diving and counting is done further below */
continue;
ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
path, show_path, &sub_size, boss_mem, 0);
if(ret<0)
goto ex;
if(ret==0)
continue;
}
if(LIBISO_ISREG(node)) {
sub_size+= iso_file_get_size((IsoFile *) node)+2048;
/*
sub_size+= iso_file_get_size((IsoFile *) node)+strlen(name)+1;
*/
}
if(sub_size>0)
(*size)+= sub_size;
Xorriso_process_msg_queues(xorriso,0);
}
if(filec<=0 || !(flag&1))
{ret= 1; goto ex;}
/* Reset iteration */
iso_dir_iter_free(iter);
iter= NULL;
Xorriso_process_msg_queues(xorriso,0);
ret= Xorriso_sorted_node_array(xorriso, dir_node, &filec, &node_array,
boss_mem, 1|2|4);
if(ret<0)
goto ex;
if(ret==0) {
no_sort= 1;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0)
goto cannot_create_iter;
}
for(i= 0; (no_sort || i<filec) && !(xorriso->request_to_abort); i++) {
if(no_sort) {
ret= iso_dir_iter_next(iter, &node);
if(ret!=1)
break;
if(!LIBISO_ISDIR(node))
continue;
} else
node= node_array[i];
sub_size= 0;
name= (char *) iso_node_get_name(node);
strcpy(show_path, rel_path);
if(Sfile_add_to_path(show_path, name, 0)<=0)
goto much_too_long;
strcpy(path, abs_path);
if(Sfile_add_to_path(path, name, 0)<=0)
goto much_too_long;
ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
path, show_path, &sub_size, boss_mem+mem, flag&1);
if(ret<0)
goto ex;
if(LIBISO_ISREG(node)) {
sub_size+= iso_file_get_size((IsoFile *) node)+2048;
/*
sub_size+= iso_tree_node_get_size((IsoFile *) node)+strlen(name)+1;
*/
}
if(sub_size>0)
(*size)+= sub_size;
report_size= sub_size/1024;
if(report_size*1024<sub_size)
report_size++;
sprintf(xorriso->result_line, "%7.f ",(double) (report_size));
sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
Text_shellsafe(show_path, sfe, 0));
Xorriso_result(xorriso, 0);
}
ret= 1;
ex:;
#ifndef Xorriso_fat_local_meM
if(sfe!=NULL)
free(sfe);
if(path!=NULL)
free(path);
if(show_path!=NULL)
free(show_path);
#endif /* ! Xorriso_fat_local_meM */
if(iter!=NULL)
iso_dir_iter_free(iter);
if(node_array!=NULL)
free((char *) node_array);
Xorriso_process_msg_queues(xorriso,0);
return(ret);
}
/* @param flag bit0= *node is already valid
bit1= add extra block for size estimation
*/
int Xorriso_fake_stbuf(struct XorrisO *xorriso, char *path, struct stat *stbuf,
IsoNode **node, int flag)
{
int ret;
IsoImage *volume;
memset((char *) stbuf, 0, sizeof(struct stat));
if(!(flag&1)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(-1);
ret= Xorriso_node_from_path(xorriso, volume, path, node, 1);
if(ret<=0)
*node= NULL;
}
if(*node==NULL)
return(0);
/* >>> stbuf->st_dev */
/* >>> stbuf->st_ino */
stbuf->st_mode= iso_node_get_permissions(*node) & 07777;
if(LIBISO_ISDIR(*node))
stbuf->st_mode|= S_IFDIR;
else if(LIBISO_ISREG(*node))
stbuf->st_mode|= S_IFREG;
else if(LIBISO_ISLNK(*node))
stbuf->st_mode|= S_IFLNK;
else if(LIBISO_ISLNK(*node))
stbuf->st_mode|= S_IFCHR;
else if(LIBISO_ISBLK(*node))
stbuf->st_mode|= S_IFBLK;
else if(LIBISO_ISFIFO(*node))
stbuf->st_mode|= S_IFIFO;
else if(LIBISO_ISSOCK(*node))
stbuf->st_mode|= S_IFSOCK;
/* >>> NG How to represent LIBISO_BOOT ? */
/* >>> With directories this should be : number of subdirs + 2 */
/* >>> ??? How to obtain RR hardlink number for other types ? */
stbuf->st_nlink= 1;
stbuf->st_uid= iso_node_get_uid(*node);
stbuf->st_gid= iso_node_get_gid(*node);
/* >>> stbuf->st_rdev */
if(LIBISO_ISREG(*node))
stbuf->st_size= iso_file_get_size((IsoFile *) *node)+ (2048 * !!(flag&2));
else
stbuf->st_size= 0;
stbuf->st_blksize= 2048;
stbuf->st_blocks= stbuf->st_size / (off_t) 2048;
if(stbuf->st_blocks * (off_t) 2048 != stbuf->st_size)
stbuf->st_blocks++;
stbuf->st_atime= iso_node_get_atime(*node);
stbuf->st_mtime= iso_node_get_mtime(*node);
stbuf->st_ctime= iso_node_get_ctime(*node);
return(1);
}
int Xorriso_iso_lstat(struct XorrisO *xorriso, char *path, struct stat *stbuf,
int flag)
{
int ret;
IsoNode *node;
ret= Xorriso_fake_stbuf(xorriso, path, stbuf, &node, 0);
if(ret>0)
return(0);
return(-1);
}
int Xorriso_sorted_dir_i(struct XorrisO *xorriso, IsoDir *dir_node,
int *filec, char ***filev, off_t boss_mem, int flag)
{
int i,j,ret;
IsoDirIter *iter= NULL;
IsoNode *node;
char *name;
off_t mem;
(*filec)= 0;
(*filev)= NULL;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0) {
cannot_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
{ret= -1; goto ex;}
}
mem= 0;
for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
name= (char *) iso_node_get_name(node);
mem+= sizeof(char *)+strlen(name)+8;
(*filec)++;
}
iso_dir_iter_free(iter);
iter= NULL;
if(*filec==0)
{ret= 1; goto ex;}
ret= Xorriso_check_temp_mem_limit(xorriso, mem+boss_mem, 2);
if(ret<=0)
goto ex;
(*filev)= (char **) calloc(*filec, sizeof(char *));
if(*filev==NULL)
{ret= -1; goto ex; }
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0)
goto cannot_iter;
for(i= 0; i<*filec; i++) {
ret= iso_dir_iter_next(iter, &node);
if(ret!=1)
break;
name= (char *) iso_node_get_name(node);
(*filev)[i]= strdup(name);
if((*filev)[i]==NULL) {
for(j= 0; j<i; j++)
if((*filev)[j]!=NULL)
free((*filev)[j]);
free((char *) (*filev));
ret= -1; goto ex;
}
}
Sort_argv(*filec, *filev, 0);
ret= 1;
ex:;
if(iter!=NULL)
iso_dir_iter_free(iter);
return(ret);
}
/* @param flag bit0= long format
bit1= do not print count of nodes
bit2= du format
bit3= print directories as themselves (ls -d)
*/
int Xorriso_ls_filev(struct XorrisO *xorriso, char *wd,
int filec, char **filev, off_t boss_mem, int flag)
{
int i, ret, was_error= 0, dfilec= 0, pass, passes;
IsoNode *node;
IsoImage *volume;
char sfe[5*SfileadrL], sfe2[5*SfileadrL], path[SfileadrL];
char link_target[SfileadrL], *rpt, **dfilev= NULL;
off_t size;
struct stat stbuf;
rpt= xorriso->result_line;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
Sort_argv(filec, filev, 0);
/* Count valid nodes, warn of invalid ones */
for(i= 0; i<filec; i++) {
ret= Xorriso_make_abs_adr(xorriso, wd, filev[i], path, 1|2|4);
if(ret<=0) {
was_error++;
continue;
}
ret= Xorriso_node_from_path(xorriso, volume, path, &node, 1);
if(ret<=0) {
sprintf(xorriso->info_text, "Not found in ISO image: %s",
Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
was_error++;
continue;
}
}
if((flag&8) && !(flag&(2|4))) {
sprintf(xorriso->info_text, "Valid ISO nodes found: %d\n", filec-was_error);
Xorriso_info(xorriso,1);
if(filec-was_error<=0)
return(!was_error);
}
passes= 1+!(flag&(4|8));
for(pass= 0; pass<passes; pass++)
for(i= 0; i<filec && !(xorriso->request_to_abort); i++) {
rpt[0]= 0;
ret= Xorriso_make_abs_adr(xorriso, wd, filev[i], path, 1|2|4);
if(ret<=0)
continue;
ret= Xorriso_fake_stbuf(xorriso, path, &stbuf, &node, (flag&4)>>1);
if(ret<=0)
continue;
if(LIBISO_ISDIR(node) && !(flag&(4|8))) {
if(pass==0)
continue;
if(filec>1) {
strcpy(xorriso->result_line, "\n");
Xorriso_result(xorriso,0);
sprintf(xorriso->result_line, "%s:\n", Text_shellsafe(filev[i], sfe,0));
Xorriso_result(xorriso,0);
}
ret= Xorriso_sorted_dir_i(xorriso,
(IsoDir *) node, &dfilec, &dfilev, boss_mem, 0);
if(ret<=0) {
/* >>> libisofs iterator loop and single item Xorriso_lsx_filev() */;
} else {
if(flag&1) {
sprintf(xorriso->result_line, "total %d\n", dfilec);
Xorriso_result(xorriso,0);
}
Xorriso_ls_filev(xorriso, path,
dfilec, dfilev, boss_mem, (flag&1)|2|8);
}
if(dfilec>0)
Sfile_destroy_argv(&dfilec, &dfilev, 0);
continue;
} else
if(pass>0)
continue;
link_target[0]= 0;
if((flag&5)==1) { /* -ls_l */
ret= Xorriso_format_ls_l(xorriso, &stbuf, 0);
if(ret<=0)
continue;
if(LIBISO_ISLNK(node)) {
if(Sfile_str(link_target, (char *) iso_symlink_get_dest(
(IsoSymlink *) node), 0)<=0)
link_target[0]= 0;
}
} else if(flag&4) { /* -du or -dus */
size= stbuf.st_size;
if(S_ISDIR(stbuf.st_mode)) {
ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
path, filev[i], &size, boss_mem, flag&1);
if(ret<0)
return(-1);
if(ret==0)
continue;
}
sprintf(rpt, "%7.f ",(double) (size/1024));
}
if(link_target[0] && (flag&5)==1)
sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s -> %s\n",
Text_shellsafe(filev[i], sfe, 0),
Text_shellsafe(link_target, sfe2, 0));
else
sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
Text_shellsafe(filev[i], sfe, 0));
Xorriso_result(xorriso, 0);
}
return(!was_error);
}
/* This function needs less buffer memory than Xorriso_ls_filev() but cannot
perform structured pattern matching as done by Xorriso_expand_pattern()
for subsequent Xorriso_ls_filev().
@param flag bit0= long format
bit1= only check for directory existence
bit2= do not apply search pattern but accept any file
*/
int Xorriso_ls(struct XorrisO *xorriso, int flag)
{
int ret, is_dir= 0, i, filec= 0, failed_at, no_sort= 0;
IsoNode *node, **node_array= NULL;
IsoDir *dir_node;
IsoImage *volume;
IsoDirIter *iter= NULL;
char sfe[5*SfileadrL], sfe2[5*SfileadrL], link_target[SfileadrL], *npt, *rpt;
struct stat stbuf;
rpt= xorriso->result_line;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
ret= Xorriso_node_from_path(xorriso, volume, xorriso->wdi, &node, 0);
if(ret<=0)
goto wdi_is_not_a_dir;
if(LIBISO_ISDIR(node))
is_dir= 1;
if(!is_dir) {
wdi_is_not_a_dir:;
sprintf(xorriso->info_text,
"Working directory path does not lead to a directory in ISO image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
if(flag&2)
{ret= 1; goto ex;}
dir_node= (IsoDir *) node;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0) {
cannot_create_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
{ret= -1; goto ex;}
}
Xorriso_process_msg_queues(xorriso,0);
for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
npt= (char *) iso_node_get_name(node);
if(!(flag&4)) {
ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
if(ret)
continue; /* no match */
}
filec++;
}
/* Reset iteration */
iso_dir_iter_free(iter);
iter= NULL;
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text, "Valid ISO nodes found: %d\n", filec);
Xorriso_info(xorriso,1);
ret= Xorriso_sorted_node_array(xorriso, dir_node, &filec, &node_array, 0,
flag&4);
if(ret<0)
goto ex;
if(ret==0) {
no_sort= 1;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0)
goto cannot_create_iter;
}
for(i= 0; i<filec && !(xorriso->request_to_abort); i++) {
if(no_sort) {
ret= iso_dir_iter_next(iter, &node);
if(ret!=1)
break;
npt= (char *) iso_node_get_name(node);
if(!(flag&4)) {
ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
if(ret)
continue; /* no match */
}
} else
node= node_array[i];
npt= (char *) iso_node_get_name(node);
link_target[0]= 0;
if(LIBISO_ISLNK(node)) {
if(Sfile_str(link_target, (char *) iso_symlink_get_dest(
(IsoSymlink *) node), 0)<=0)
link_target[0]= 0;
}
rpt[0]= 0;
if(flag&1) {
ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
if(ret<=0)
continue;
ret= Xorriso_format_ls_l(xorriso, &stbuf, 0);
if(ret<=0)
continue;
}
if(link_target[0] && (flag&1))
sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s -> %s\n",
Text_shellsafe(npt, sfe, 0),
Text_shellsafe(link_target, sfe2, 0));
else
sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
Text_shellsafe(npt, sfe, 0));
Xorriso_result(xorriso, 0);
}
ret= 1;
ex:;
if(iter!=NULL)
iso_dir_iter_free(iter);
Xorriso_process_msg_queues(xorriso,0);
if(node_array!=NULL)
free((char *) node_array);
return(1);
}
/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
Set to NULL if calling this function from outside ISO world
*/
int Xorriso_rename(struct XorrisO *xorriso, void *boss_iter,
char *origin, char *dest, int flag)
{
int ret, ol, dest_ret;
char sfe[5*SfileadrL], eff_dest[SfileadrL], dir_adr[SfileadrL], *cpt;
char *leafname, eff_origin[SfileadrL], sfe2[5*SfileadrL], *old_leafname;
IsoImage *volume;
IsoDir *origin_dir, *dest_dir;
IsoNode *node, *iso_node;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, origin, eff_origin, 0);
if(ret<=0)
return(ret);
dest_ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest,1);
if(dest_ret<0)
return(dest_ret);
if(dest_ret==0) { /* obtain eff_dest address despite it does not exist */
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest, 2);
if(ret<=0)
return(ret);
}
/* Prevent that destination is a subordinate of origin
(that would be a black hole plopping out of the universe) */
ol= strlen(eff_origin);
if(ol==0) {
sprintf(xorriso->info_text, "May not rename root directory");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
} else if(strcmp(eff_origin, eff_dest)==0) {
sprintf(xorriso->info_text, "Ignored attempt to rename %s to itself",
Text_shellsafe(eff_origin,sfe,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
return(0);
} else if(strncmp(eff_origin, eff_dest, ol)==0 &&
(eff_dest[ol]==0 || eff_dest[ol]=='/')) {
sprintf(xorriso->info_text,
"May not rename %s to its own sub address %s",
Text_shellsafe(eff_origin,sfe,0), Text_shellsafe(eff_dest,sfe2,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
/* Check whether destination exists and may be not overwriteable */
if(dest_ret==2 && xorriso->do_overwrite!=1) {
sprintf(xorriso->info_text, "Renaming may not overwrite directory: %s",
Text_shellsafe(eff_dest, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
} else if (dest_ret==1 && !xorriso->do_overwrite) {
sprintf(xorriso->info_text, "Renaming may not overwite: %s",
Text_shellsafe(eff_dest, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
} else if(dest_ret>0) {
ret= Xorriso_rmi(xorriso, boss_iter, eff_dest, 1|8);
if(ret<=0)
return(0);
if(ret==3) {
sprintf(xorriso->info_text, "User revoked renaming of: %s",
Text_shellsafe(eff_origin, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(0);
}
}
/* Ensure existence of destination directory */
strcpy(dir_adr, eff_dest);
cpt= strrchr(dir_adr, '/');
if(cpt==NULL)
cpt= dir_adr+strlen(dir_adr);
*cpt= 0;
if(dir_adr[0]!=0) {
ret= Xorriso_graft_in(xorriso, boss_iter, NULL, dir_adr, 1);
if(ret<=0)
return(ret);
}
/* Move node */
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
Xorriso_node_from_path(xorriso, volume, dir_adr, &iso_node, 0);
dest_dir= (IsoDir *) iso_node;
strcpy(dir_adr, eff_origin);
cpt= strrchr(dir_adr, '/');
if(cpt==NULL)
cpt= dir_adr+strlen(dir_adr);
*cpt= 0;
Xorriso_node_from_path(xorriso, volume, dir_adr, &iso_node, 0);
origin_dir= (IsoDir *) iso_node;
Xorriso_node_from_path(xorriso, volume, eff_origin, &node, 0);
if(dest_dir==NULL || origin_dir==NULL || node==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"Internal error on rename: confirmed node turns out as NULL");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
ret= iso_node_take(node);
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot take", 0, "FATAL",1);
sprintf(xorriso->info_text,
"Internal error on rename: failed to take node");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
ret= iso_dir_add_node(dest_dir, node, 0);
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot add", 0, "FATAL", 1);
sprintf(xorriso->info_text,
"Internal error on rename: failed to insert node");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
leafname= strrchr(eff_dest, '/');
if(leafname==NULL)
leafname= eff_dest;
else
leafname++;
old_leafname= (char *) iso_node_get_name(node);
if(strcmp(leafname, old_leafname)!=0)
ret= iso_node_set_name(node, leafname);
else
ret= 1;
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot set name", 0,
"FATAL", 1);
sprintf(xorriso->info_text, "Internal error on rename: failed to set name");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(-1);
}
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
/* @param flag bit0= do not produce info message on success
@return 1=success,
0=was already directory, -1=was other type, -2=other error
*/
int Xorriso_mkdir(struct XorrisO *xorriso, char *path, int flag)
{
int ret;
char eff_path[SfileadrL], sfe[5*SfileadrL];
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 1);
if(ret<0)
return(-2);
if(ret>0) {
sprintf(xorriso->info_text,"-mkdir: Address already existing %s",
Text_shellsafe(eff_path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0,
(ret==2 ? "WARNING" : "FAILURE"), 0);
return(-1+(ret==2));
}
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 2);
if(ret<0)
return(-2);
ret= Xorriso_graft_in(xorriso, NULL, NULL, eff_path, 1);
if(ret<=0)
return(-2);
if(!(flag&1)) {
sprintf(xorriso->info_text, "Created directory in ISO image: %s\n",
Text_shellsafe(eff_path,sfe,0));
Xorriso_info(xorriso, 0);
}
return(1);
}
/* @param flag bit0= count results rather than storing them
bit1= this is a recursion
bit2= prepend wd (automatically done if wd[0]!=0)
*/
int Xorriso_obtain_pattern_files_i(
struct XorrisO *xorriso, char *wd, IsoDir *dir,
int *filec, char **filev, int count_limit, off_t *mem,
int *dive_count, int flag)
{
int ret, failed_at;
IsoDirIter *iter= NULL;
IsoNode *node;
char *name;
#ifdef Xorriso_fat_local_meM
char adr[SfileadrL];
#else /* Xorriso_fat_local_meM */
char *adr= NULL;
adr= malloc(SfileadrL);
if(adr==NULL) {
Xorriso_no_malloc_memory(xorriso, &adr, 0);
{ret= -1; goto ex;}
}
#endif /* ! Xorriso_fat_local_meM */
if(!(flag&2))
*dive_count= 0;
else
(*dive_count)++;
ret= Xorriso_check_for_root_pattern(xorriso, filec, filev, count_limit,
mem, (flag&1)|2);
if(ret!=2)
goto ex;
ret= iso_dir_get_children(dir, &iter);
if(ret<0) {
Xorriso_cannot_create_iter(xorriso, ret, 0);
{ret= -1; goto ex;}
}
while(iso_dir_iter_next(iter, &node) == 1) {
name= (char *) iso_node_get_name(node);
ret= Xorriso_make_abs_adr(xorriso, wd, name, adr, flag&4);
if(ret<=0)
goto ex;
ret= Xorriso_regexec(xorriso, adr, &failed_at, 1);
if(ret) { /* no match */
if(failed_at <= *dive_count) /* no hope for a match */
continue;
if(!LIBISO_ISDIR(node)) {
/* >>> How to deal with softlinks ? */
continue;
}
/* dive deeper */
ret= Xorriso_obtain_pattern_files_i(
xorriso, adr, (IsoDir *) node,
filec, filev, count_limit, mem, dive_count, flag|2);
if(ret<=0)
goto ex;
} else {
ret= Xorriso_register_matched_adr(xorriso, adr, count_limit,
filec, filev, mem, (flag&1)|2);
if(ret<=0)
goto ex;
}
}
ret= 1;
ex:;
#ifndef Xorriso_fat_local_meM
if(adr!=NULL)
free(adr);
#endif /* ! Xorriso_fat_local_meM */
if(flag&2)
(*dive_count)--;
return(ret);
}
/* @param flag bit0= a match count !=1 is a FAILURE event
bit1= with bit0 tolerate 0 matches if pattern is a constant
*/
int Xorriso_expand_pattern(struct XorrisO *xorriso,
int num_patterns, char **patterns, int extra_filec,
int *filec, char ***filev, off_t *mem, int flag)
{
int ret, count= 0, abs_adr= 0, i, was_count, was_filec;
int nonconst_mismatches= 0, dive_count= 0;
char sfe[5*SfileadrL];
IsoImage *volume;
IsoDir *dir= NULL, *root_dir;
IsoNode *iso_node;
*filec= 0;
*filev= NULL;
xorriso->search_mode= 3;
xorriso->structured_search= 1;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
root_dir= iso_image_get_root(volume);
if(root_dir==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"While expanding pattern : Cannot obtain root node of ISO image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
ret= -1; goto ex;
}
for(i= 0; i<num_patterns; i++) {
ret= Xorriso_prepare_expansion_pattern(xorriso, patterns[i], 0);
if(ret<=0)
return(ret);
if(ret==2)
abs_adr= 4;
if(patterns[i][0]=='/' || abs_adr) {
dir= root_dir;
abs_adr= 4;
} else {
/* This is done so late to allow the following:
It is not an error if xorriso->wdi does not exist yet, but one may
not use it as base for relative address searches.
*/
ret= Xorriso_node_from_path(xorriso, volume, xorriso->wdi, &iso_node, 1);
dir= (IsoDir *) iso_node;
if(ret<=0) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"While expanding pattern %s : Working directory does not exist in ISO image",
Text_shellsafe(patterns[i], sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
if(!LIBISO_ISDIR((IsoNode *) dir)) {
sprintf(xorriso->info_text,
"Working directory path does not lead to a directory in ISO image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
}
/* count the matches */
was_count= count;
ret= Xorriso_obtain_pattern_files_i(xorriso, "", dir, &count, NULL, 0,
mem, &dive_count, 1 | abs_adr);
if(ret<=0)
goto ex;
if(was_count==count && strcmp(patterns[i],"*")!=0 && (flag&3)!=1) {
count++;
Xorriso_eval_nonmatch(xorriso, patterns[i], &nonconst_mismatches, mem, 0);
}
}
ret= Xorriso_check_matchcount(xorriso, count, nonconst_mismatches,
num_patterns, patterns, (flag&1)|2);
if(ret<=0)
goto ex;
count+= extra_filec;
mem+= extra_filec*sizeof(char *);
if(count<=0)
{ret= 0; goto ex;}
ret= Xorriso_alloc_pattern_mem(xorriso, *mem, count, filev, 0);
if(ret<=0)
goto ex;
/* now store addresses */
for(i= 0; i<num_patterns; i++) {
ret= Xorriso_prepare_expansion_pattern(xorriso, patterns[i], 0);
if(ret<=0)
return(ret);
if(ret==2)
abs_adr= 4;
was_filec= *filec;
ret= Xorriso_obtain_pattern_files_i(xorriso, "", dir, filec, *filev, count,
mem, &dive_count, abs_adr);
if(ret<=0)
goto ex;
if(was_filec == *filec && strcmp(patterns[i],"*")!=0) {
(*filev)[*filec]= strdup(patterns[i]);
if((*filev)[*filec]==NULL) {
(*mem)= strlen(patterns[i])+1;
Xorriso_no_pattern_memory(xorriso, *mem, 0);
ret= -1; goto ex;
}
(*filec)++;
}
}
ret= 1;
ex:;
if(ret<=0) {
if(filev!=NULL)
Sfile_destroy_argv(&count, filev, 0);
*filec= 0;
}
return(ret);
}
int Xorriso_set_st_mode(struct XorrisO *xorriso, char *in_path,
mode_t mode_and, mode_t mode_or, int flag)
{
mode_t mode= 0;
int ret;
IsoNode *node;
char sfe[5*SfileadrL], path[SfileadrL];
ret= Xorriso_get_node_by_path(xorriso, in_path, path, &node, 0);
if(ret<=0)
return(ret);
mode= iso_node_get_permissions(node);
mode= (mode & mode_and) | mode_or;
iso_node_set_permissions(node, mode);
iso_node_set_ctime(node, time(NULL));
sprintf(xorriso->info_text,"Permissions now: %-5.5o %s",
mode, Text_shellsafe(path, sfe, 0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_set_uid(struct XorrisO *xorriso, char *in_path, uid_t uid,
int flag)
{
int ret;
IsoNode *node;
ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
if(ret<=0)
return(ret);
iso_node_set_uid(node, uid);
iso_node_set_ctime(node, time(NULL));
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
int Xorriso_set_gid(struct XorrisO *xorriso, char *in_path, gid_t gid,
int flag)
{
int ret;
IsoNode *node;
ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
if(ret<=0)
return(ret);
iso_node_set_gid(node, gid);
iso_node_set_ctime(node, time(NULL));
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
/* @parm flag bit0= atime, bit1= ctime, bit2= mtime, bit8=no auto ctime */
int Xorriso_set_time(struct XorrisO *xorriso, char *in_path, time_t t,
int flag)
{
int ret;
IsoNode *node;
ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
if(ret<=0)
return(ret);
if(flag&1)
iso_node_set_atime(node, t);
if(flag&2)
iso_node_set_ctime(node, t);
if(flag&4)
iso_node_set_mtime(node, t);
if(!(flag&(2|256)))
iso_node_set_ctime(node, time(NULL));
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
return(1);
}
/* @param flag bit0= not a command parameter (directory iteration or recursion)
bit1= do not count deleted files with rm and rm_r
*/
int Xorriso_findi_action(struct XorrisO *xorriso, struct FindjoB *job,
IsoDirIter *boss_iter, off_t boss_mem,
char *abs_path, char *show_path,
IsoNode *node, int depth, int flag)
{
int ret= 0, type, action= 0, hflag;
uid_t user= 0;
gid_t group= 0;
time_t date= 0;
mode_t mode_or= 0, mode_and= ~1;
char *target, sfe[5*SfileadrL], *iso_prefix;
struct FindjoB *subjob;
struct stat dir_stbuf;
action= Findjob_get_action_parms(job, &target, &user, &group,
&mode_and, &mode_or, &type, &date, &subjob, 0);
if(action<0)
action= 0;
hflag= 16*!(flag&2);
if(action==1) { /* rm (including rmdir) */
ret= Xorriso_fake_stbuf(xorriso, abs_path, &dir_stbuf, &node, 1);
if(ret>0) {
if(S_ISDIR(dir_stbuf.st_mode))
hflag= 2;
ret= Xorriso_rmi(xorriso, boss_iter, abs_path, hflag);
}
} else if(action==2) { /* rm_r */
ret= Xorriso_rmi(xorriso, boss_iter, abs_path, 1|hflag);
} else if(action==3) {
/* >>> mv target */;
} else if(action==4) { /* chown */
ret= Xorriso_set_uid(xorriso, abs_path, user, 0);
} else if(action==5) { /* chgrp */
ret= Xorriso_set_gid(xorriso, abs_path, group, 0);
} else if(action==6) { /* chmod */
ret= Xorriso_set_st_mode(xorriso, abs_path, mode_and, mode_or, 0);
} else if(action==7) { /* alter_date */
ret= Xorriso_set_time(xorriso, abs_path, date, type&7);
} else if(action==8) { /* lsdl */
ret= Xorriso_ls_filev(xorriso, "", 1, &abs_path, (off_t) 0, 1|2|8);
} else if(action>=9 && action<=13) { /* actions which have own findjobs */
Findjob_set_start_path(subjob, abs_path, 0);
ret= Xorriso_findi(xorriso, subjob, boss_iter, boss_mem, NULL,
abs_path, &dir_stbuf, depth, 1);
} else if(action==14 || action==17) { /* compare , update */
Findjob_get_start_path(job, &iso_prefix, 0);
ret= Xorriso_find_compare(xorriso, (void *) boss_iter, abs_path,
iso_prefix, target, (action==17)|((flag&1)<<1));
if(ret>=0)
ret= 1;
} else if(action==16 || action==18) { /* not_in_iso , add_missing */
;
} else { /* includes : 15 in_iso */
sprintf(xorriso->result_line, "%s\n", Text_shellsafe(show_path, sfe, 0));
Xorriso_result(xorriso, 0);
ret= 1;
}
return(ret);
}
int Xorriso__node_lba_cmp(const void *node1, const void *node2)
{
uint32_t lba1= 0, lba2= 0;
int ret;
ret = iso_node_get_old_image_lba(*((IsoNode **) node1), &lba1, 0);
if(ret!=1)
lba1= 0;
ret = iso_node_get_old_image_lba(*((IsoNode **) node2), &lba2, 0);
if(ret!=1)
lba1= 0;
return(lba1-lba2);
}
/* The caller shall make no assumptions about the meaning of iter, node_array,
node_count, node_idx ! They are just opaque handles for which the caller
provides the memory of proper type.
@param flag bit0= initialize iteration
bit1= action needs full freedom of object manipulation
bit2= action needs LBA sorted iteration
bit31= end iteration (mandatory !)
*/
int Xorriso_findi_iter(struct XorrisO *xorriso, IsoDir *dir_node, off_t *mem,
IsoDirIter **iter,
IsoNode ***node_array, int *node_count, int *node_idx,
IsoNode **iterated_node, int flag)
{
int ret, i;
IsoNode *node;
off_t new_mem= 0;
char mem_text[80], limit_text[80];
if(flag&1) {
*node_array= NULL;
*node_count= -1;
*node_idx= 0;
*iter= NULL;
ret= iso_dir_get_children(dir_node, iter);
if(ret<0) {
cannot_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
return(-1);
}
if((flag&2)|(flag&4)) {
/* copy list of nodes and prepare soft iterator */
*node_count= 0;
while(iso_dir_iter_next(*iter, &node) == 1)
(*node_count)++;
iso_dir_iter_free(*iter);
*iter= NULL;
new_mem= ((*node_count)+1) * sizeof(IsoNode *);
if(new_mem > xorriso->temp_mem_limit) {
Sfile_scale((double) new_mem, mem_text, 5,1e4, 0);
Sfile_scale((double) xorriso->temp_mem_limit, limit_text, 5,1e4, 0);
sprintf(xorriso->info_text,
"Stacked directory snapshots exceed -temp_mem_limit (%s > %s)",
mem_text, limit_text);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
*node_count= -1;
return(-1);
}
(*node_array)= (IsoNode **) calloc((*node_count)+1, sizeof(IsoNode *));
if(*node_array == NULL) {
sprintf(xorriso->info_text,
"Could not allocate inode list of %.f bytes",
((double) (*node_count)+1) * (double) sizeof(IsoNode *));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
*node_count= -1;
return(-1);
}
*mem= new_mem;
ret= iso_dir_get_children(dir_node, iter);
if(ret<0)
goto cannot_iter;
while(iso_dir_iter_next(*iter, &node) == 1 && *node_idx < *node_count) {
(*node_array)[*node_idx]= node;
iso_node_ref(node);
(*node_idx)++;
}
iso_dir_iter_free(*iter);
*iter= NULL;
*node_count= *node_idx;
*node_idx= 0;
if((flag&4) && *node_count>1)
qsort(*node_array, *node_count, sizeof(IsoNode *),
Xorriso__node_lba_cmp);
}
}
if(flag&(1<<31)) {
if(*node_count>=0 && *node_array!=NULL) {
for(i= 0; i<*node_count; i++)
iso_node_unref((*node_array)[i]);
free(*node_array);
*node_array= NULL;
*node_count= -1;
*node_idx= 0;
} else {
if(*iter!=NULL)
iso_dir_iter_free(*iter);
*iter= NULL;
}
}
if(flag&(1|(1<<31)))
return(1);
if(*node_count>=0) {
/* return next node_array element */
if(*node_idx>=*node_count)
return(0);
*iterated_node= (*node_array)[*node_idx];
(*node_idx)++;
} else {
ret= iso_dir_iter_next(*iter, iterated_node);
return(ret == 1);
}
return(1);
}
/* @param flag bit0= recursion
bit1= do not count deleted files with rm and rm_r
*/
int Xorriso_findi(struct XorrisO *xorriso, struct FindjoB *job,
void *boss_iter, off_t boss_mem,
void *dir_node_generic, char *dir_path,
struct stat *dir_stbuf, int depth, int flag)
{
int ret, action= 0, hflag;
IsoDirIter *iter= NULL;
IsoDir *dir_node= NULL;
IsoNode *node, *iso_node;
IsoImage *volume;
struct stat stbuf;
char *name;
off_t mem;
IsoNode **node_array= NULL;
int node_count, node_idx;
#ifdef Xorriso_fat_local_meM
char path[SfileadrL], abs_path[SfileadrL];
#else /* Xorriso_fat_local_meM */
char *path= NULL, *abs_path= NULL;
path= malloc(SfileadrL);
abs_path= malloc(SfileadrL);
if(path==NULL || abs_path==NULL) {
Xorriso_no_malloc_memory(xorriso, &path, 0);
{ret= -1; goto ex;}
}
#endif /* ! Xorriso_fat_local_meM */
action= Findjob_get_action(job, 0);
if(action<0)
action= 0;
dir_node= (IsoDir *) dir_node_generic;
if(dir_node==NULL) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
{ret= -1; goto ex;}
ret= Xorriso_make_abs_adr(xorriso, xorriso->wdi, dir_path, path, 1|2|4);
if(ret<=0)
goto ex;
ret= Xorriso_node_from_path(xorriso, volume, path, &iso_node, 0);
dir_node= (IsoDir *) iso_node;
if(ret<=0)
{ret= 0; goto ex;}
ret= Xorriso_fake_stbuf(xorriso, "", dir_stbuf, &iso_node, 1);
dir_node= (IsoDir *) iso_node;
if(ret<=0)
goto ex;
name= strrchr(dir_path, '/');
if(name==NULL)
name= dir_path;
else
name++;
ret= Findjob_test(job, name, NULL, dir_stbuf, depth, 0);
if(ret<0)
goto ex;
if(ret>0) {
ret= Xorriso_findi_action(xorriso, job,
(IsoDirIter *) boss_iter, boss_mem,
path, dir_path, (IsoNode *) dir_node, depth,
flag&(1|2));
if(ret<=0)
goto ex;
}
}
if(!LIBISO_ISDIR((IsoNode *) dir_node))
{ret= 2; goto ex;}
mem= boss_mem;
hflag= 1;
if(action==1 || action==2 || action==3 || action==14)
hflag|= 2; /* need freedom to manipulate image */
if(action==14 || action==17)
hflag|= 4; /* need LBA sorted iteration for good data reading performance */
ret= Xorriso_findi_iter(xorriso, dir_node, &mem,
&iter, &node_array, &node_count, &node_idx,
&node, hflag);
if(ret<=0)
goto ex;
while(1) {
ret= Xorriso_findi_iter(xorriso, dir_node, &mem, &iter,
&node_array, &node_count, &node_idx, &node, 0);
if(ret<0)
goto ex;
if(ret==0 || xorriso->request_to_abort)
break;
name= (char *) iso_node_get_name(node);
ret= Xorriso_make_abs_adr(xorriso, dir_path, name, path, 4);
if(ret<=0)
goto ex;
ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
if(ret<0)
goto ex;
if(ret==0)
continue;
ret= Findjob_test(job, name, dir_stbuf, &stbuf, depth, 0);
if(ret<0)
goto ex;
if(ret>0) {
ret= Xorriso_make_abs_adr(xorriso, xorriso->wdi, path, abs_path, 1|2|4);
if(ret<=0)
goto ex;
ret= Xorriso_findi_action(xorriso, job, iter, mem,
abs_path, path, node, depth, 1|(flag&2));
if(ret<=0) {
if(Xorriso_eval_problem_status(xorriso, ret, 1|2)<0)
goto ex;
}
}
if(S_ISDIR(stbuf.st_mode)) {
ret= Xorriso_findi(xorriso, job, (void *) iter, mem,
(void *) node, path, &stbuf, depth+1, flag|1);
if(ret<0)
goto ex;
}
}
ret= 1;
ex:;
#ifndef Xorriso_fat_local_meM
if(path!=NULL)
free(path);
if(abs_path!=NULL)
free(abs_path);
#endif /* ! Xorriso_fat_local_meM */
Xorriso_process_msg_queues(xorriso,0);
#ifdef Xorriso_findi_new_iteR
Xorriso_findi_iter(xorriso, dir_node, &mem, &iter, &node_array, &node_count,
&node_idx, &node, (1<<31));
#else
if(iter!=NULL)
iso_dir_iter_free(iter);
#endif
return(ret);
}
/* @param flag bit0= do not mark image as changed */
int Xorriso_set_volid(struct XorrisO *xorriso, char *volid, int flag)
{
int ret;
IsoImage *volume;
if(xorriso->in_volset_handle == NULL)
return(2);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
iso_image_set_volume_id(volume, volid);
if(!(flag&1))
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Volume ID: '%s'",iso_image_get_volume_id(volume));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
return(1);
}
int Xorriso_get_volid(struct XorrisO *xorriso, char volid[33], int flag)
{
int ret;
IsoImage *volume;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
strncpy(volid, iso_image_get_volume_id(volume), 32);
volid[32]= 0;
return(1);
}
/* @param flag bit0= do not mark image as changed */
int Xorriso_set_publisher(struct XorrisO *xorriso, char *name, int flag)
{
int ret;
IsoImage *volume;
if(xorriso->in_volset_handle == NULL)
return(2);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(ret);
iso_image_set_publisher_id(volume, name);
if(!(flag&1))
xorriso->volset_change_pending= 1;
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,"Publisher: '%s'",
iso_image_get_publisher_id(volume));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
return(1);
}
/* @param flag bit0=prepare for a burn run */
int Xorriso_set_abort_severity(struct XorrisO *xorriso, int flag)
{
int ret;
/* ??? <<< On MISHAP use FAILURE as abort severity known to libisofs.
On ERRFILE use NEVER.
The pacifier loop will care for canceling libburn on MISHAP
and thus also cancel the image generation.
with libisofs-0.6.4 this should not be necessary
Shall it be uphold anyway ?
*/
if((flag&1) && strcmp(xorriso->abort_on_text, "MISHAP")==0)
ret= iso_set_abort_severity("FAILURE");
else if((flag&1) && strcmp(xorriso->abort_on_text, "ERRFILE")==0)
ret= iso_set_abort_severity("NEVER");
else
ret= iso_set_abort_severity(xorriso->abort_on_text);
return(ret>=0);
}
int Xorriso_report_lib_versions(struct XorrisO *xorriso, int flag)
{
int major, minor, micro;
int req_major, req_minor, req_micro;
iso_lib_version(&major, &minor, &micro);
isoburn_libisofs_req(&req_major, &req_minor, &req_micro);
sprintf(xorriso->result_line,
"libisofs in use : %d.%d.%d (min. %d.%d.%d)\n",
major, minor, micro, req_major, req_minor, req_micro);
Xorriso_result(xorriso, 0);
burn_version(&major, &minor, &micro);
isoburn_libburn_req(&req_major, &req_minor, &req_micro);
sprintf(xorriso->result_line,
"libburn in use : %d.%d.%d (min. %d.%d.%d)\n",
major, minor, micro, req_major, req_minor, req_micro);
Xorriso_result(xorriso, 0);
isoburn_version(&major, &minor, &micro);
sprintf(xorriso->result_line,
"libisoburn in use : %d.%d.%d (min. %d.%d.%d)\n",
major, minor, micro,
isoburn_header_version_major, isoburn_header_version_minor,
isoburn_header_version_micro);
Xorriso_result(xorriso, 0);
return(1);
}
/* @param flag bit0= -inq
bit1= -checkdrive
*/
int Xorriso_atip(struct XorrisO *xorriso, int flag)
{
int ret, profile_number= 0;
char *respt, profile_name[80];
double x_speed_max, x_speed_min= -1.0;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
enum burn_disc_status s;
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to print drive and media info", 2);
if(ret<=0)
return(0);
respt= xorriso->result_line;
sprintf(respt, "Device type :");
ret= burn_drive_get_drive_role(drive);
if(ret==0)
sprintf(respt+strlen(respt), "%s\n", "Emulated (null-drive)");
else if(ret==2)
sprintf(respt+strlen(respt), "%s\n",
"Emulated (stdio-drive, 2k random read-write)");
else if(ret==3)
sprintf(respt+strlen(respt), "%s\n",
"Emulated (stdio-drive, sequential write-only)");
else if(ret!=1)
sprintf(respt+strlen(respt), "%s\n","Emulated (stdio-drive)");
else
sprintf(respt+strlen(respt), "%s\n","Removable CD-ROM");
sprintf(respt+strlen(respt), "Vendor_info : '%s'\n",dinfo->vendor);
sprintf(respt+strlen(respt), "Identifikation : '%s'\n",dinfo->product);
sprintf(respt+strlen(respt), "Revision : '%s'\n",dinfo->revision);
Xorriso_result(xorriso,1);
if(flag&1)
return(1);
sprintf(respt, "Driver flags : BURNFREE\n");
sprintf(respt+strlen(respt), "Supported modes: SAO TAO\n");
Xorriso_result(xorriso,1);
if(flag&2)
return(1);
s= burn_disc_get_status(drive);
ret= burn_disc_get_profile(drive,&profile_number,profile_name);
if(ret<=0) {
profile_number= 0;
strcpy(profile_name, "-unidentified-");
}
if(s != BURN_DISC_UNSUITABLE) {
ret= burn_disc_read_atip(drive);
if(ret>0) {
ret= burn_drive_get_min_write_speed(drive);
x_speed_min= ((double) ret)/176.4;
}
}
if(s==BURN_DISC_EMPTY) {
sprintf(respt, "Current: none\n");
Xorriso_result(xorriso,1);
return(1);
} else
sprintf(respt, "Current: %s\n",profile_name);
Xorriso_result(xorriso,1);
if(strstr(profile_name,"DVD")==profile_name) {
sprintf(respt, "book type: %s (emulated booktype)\n", profile_name);
Xorriso_result(xorriso,1);
sprintf(respt, "xorriso: message for sdvdbackup: \"(growisofs mode Restricted Overwrite)\"\n");
Xorriso_result(xorriso,1);
} else {
sprintf(respt, "ATIP info from disk:\n");
Xorriso_result(xorriso,1);
if(burn_disc_erasable(drive))
sprintf(respt, " Is erasable\n");
else
sprintf(respt, " Is not erasable\n");
Xorriso_result(xorriso,1);
{ int start_lba,end_lba,min,sec,fr;
ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0);
if(ret>0) {
burn_lba_to_msf(start_lba,&min,&sec,&fr);
sprintf(respt, " ATIP start of lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n",
start_lba,min,sec,fr);
Xorriso_result(xorriso,1);
burn_lba_to_msf(end_lba,&min,&sec,&fr);
sprintf(respt, " ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
end_lba,min,sec,fr);
Xorriso_result(xorriso,1);
}
}
ret= burn_drive_get_write_speed(drive);
x_speed_max= ((double) ret)/176.4;
if(x_speed_min<0)
x_speed_min= x_speed_max;
sprintf(respt,
" 1T speed low: %.f 1T speed high: %.f\n",x_speed_min,x_speed_max);
Xorriso_result(xorriso,1);
}
return(1);
}
int Xorriso_burn_track(struct XorrisO *xorriso, char *track_source, int flag)
{
int ret, fd, unpredicted_size, profile_number, is_cd= 0;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
struct burn_write_opts *burn_options;
struct burn_disc *disc= NULL;
struct burn_session *session;
struct burn_track *track;
struct stat stbuf;
off_t fixed_size= 0;
struct burn_source *data_src, *fifo_src;
enum burn_disc_status disc_state;
char reasons[BURN_REASONS_LEN], sfe[5*SfileadrL], profile_name[80];
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to burn track", 2);
if(ret<=0)
return(0);
ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
if(ret<=0)
goto ex;
disc= burn_disc_create();
session= burn_session_create();
ret= burn_disc_add_session(disc,session,BURN_POS_END);
if(ret==0) {
/* >>> */;
goto ex;
}
track= burn_track_create();
if(track_source[0] == '-' && track_source[1] == 0) {
fd= 0;
} else {
fd= open(track_source, O_RDONLY);
if(fd>=0)
if(fstat(fd,&stbuf)!=-1)
if((stbuf.st_mode&S_IFMT)==S_IFREG)
fixed_size= stbuf.st_size;
}
if(fixed_size==0)
unpredicted_size= 1;
data_src= NULL;
if(fd>=0)
data_src= burn_fd_source_new(fd, -1, fixed_size);
if(data_src==NULL) {
sprintf(xorriso->info_text, "Could not open data source %s",
Text_shellsafe(track_source,sfe,0));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
ret= 0; goto ex;
}
fifo_src= burn_fifo_source_new(data_src, 2048, xorriso->fs, 0);
if(fifo_src == NULL) {
sprintf(xorriso->info_text, "Could not create fifo object of 4 MB");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
ret= 0; goto ex;
}
xorriso->pacifier_fifo= fifo_src;
if(burn_track_set_source(track, fifo_src)!=BURN_SOURCE_OK) {
sprintf(xorriso->info_text,
"Cannot attach source object to track object");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
ret= 0; goto ex;
}
burn_session_add_track(session, track, BURN_POS_END);
burn_source_free(data_src);
disc_state = burn_disc_get_status(drive);
if(disc_state == BURN_DISC_BLANK) {
/* ok */;
} else if(disc_state == BURN_DISC_APPENDABLE) {
if(!isoburn_needs_emulation(drive)) {
sprintf(xorriso->info_text,
"Appendable media with data detected. Need blank media.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
} else {
if(disc_state == BURN_DISC_FULL) {
sprintf(xorriso->info_text,
"Closed media with data detected. Need blank media.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
if(burn_disc_erasable(drive)) {
sprintf(xorriso->info_text, "Try --blank_fast\n");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
}
} else if(disc_state == BURN_DISC_EMPTY) {
sprintf(xorriso->info_text, "No media detected in drive");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
} else {
sprintf(xorriso->info_text,
"Cannot recognize state of drive and media");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
}
ret= 0; goto ex;
}
if(burn_write_opts_auto_write_type(burn_options, disc, reasons, 0) ==
BURN_WRITE_NONE) {
sprintf(xorriso->info_text,
"Failed to find a suitable write mode with this media.\n");
sprintf(xorriso->info_text+strlen(xorriso->info_text),
"Reasons given:\n%s", reasons);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
ret= Xorriso_get_profile(xorriso, &profile_number, profile_name, 2);
is_cd= (ret==2);
if(isoburn_needs_emulation(drive))
burn_write_opts_set_start_byte(burn_options, (off_t) 0);
ret= Xorriso_sanitize_image_size(xorriso, drive, disc, burn_options, 2);
if(ret<=0)
goto ex;
xorriso->run_state= 1; /* Indicate that burning has started */
burn_disc_write(burn_options, disc);
ret= Xorriso_pacifier_loop(xorriso, drive, 1|(is_cd<<4));
if(ret<=0)
goto ex;
if(!burn_drive_wrote_well(drive)) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"libburn indicates failure with writing.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
sprintf(xorriso->info_text, "Writing completed sucessfully.\n\n");
Xorriso_info(xorriso, 0);
ret= 1;
ex:;
Xorriso_process_msg_queues(xorriso,0);
if(disc!=NULL)
burn_disc_free(disc);
if(xorriso->pacifier_fifo!=NULL)
burn_source_free(xorriso->pacifier_fifo);
xorriso->pacifier_fifo= NULL;
xorriso->run_state= 0; /* Indicate that burning has ended */
return(ret);
}
/* @param flag bit1= outdev rather than indev
@return <0 error, 0 = no profile to see , 1= ok , 2= ok, is CD profile
*/
int Xorriso_get_profile(struct XorrisO *xorriso, int *profile_number,
char profile_name[80], int flag)
{
int ret;
struct burn_drive_info *dinfo;
struct burn_drive *drive;
*profile_number= 0;
profile_name[0]= 0;
if(xorriso->out_drive_handle==NULL)
return(0);
ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
"on attempt to determine media type", flag&2);
if(ret<=0)
return(0);
ret=burn_disc_get_profile(drive, profile_number, profile_name);
if(ret<=0)
return(ret);
if(*profile_number==0x08 || *profile_number==0x09 || *profile_number==0x0a)
return(2);
return(0);
}
int Xorriso_iso_file_open(struct XorrisO *xorriso, char *pathname,
void **stream, int flag)
{
int ret;
char eff_path[SfileadrL];
IsoNode *node= NULL;
IsoFile *filenode= NULL;
IsoStream *iso_stream= NULL;
#ifdef Libisofs_lba_tesT
uint32_t lba;
#endif
*stream= NULL;
ret= Xorriso_get_node_by_path(xorriso, pathname, eff_path, &node, 0);
if(ret<=0)
return(ret);
if(!LIBISO_ISREG(node)) {
sprintf(xorriso->info_text,
"Given path does not lead to a regular data file in the image");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
#ifdef Libisofs_lba_tesT
ret = iso_node_get_old_image_lba(node, &lba, 0);
sprintf(xorriso->info_text, "%s : ret= %d , LBA= %lx",
pathname, ret, (unsigned long) lba);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
#endif
filenode= (IsoFile *) node;
iso_stream= iso_file_get_stream(filenode);
if(iso_stream==NULL) {
Xorriso_process_msg_queues(xorriso,0);
sprintf(xorriso->info_text,
"Could not obtain source stream of file in the image for reading");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
ret= iso_stream_open(iso_stream);
if(ret<0) {
sprintf(xorriso->info_text,
"Could not open data file in the image for reading");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
if(!iso_stream_is_repeatable(iso_stream)) {
sprintf(xorriso->info_text,
"The data production of the file in the image is one-time only");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
iso_stream_close(iso_stream);
return(0);
}
Xorriso_process_msg_queues(xorriso,0);
*stream= iso_stream;
return(1);
}
int Xorriso_iso_file_read(struct XorrisO *xorriso, void *stream, char *buf,
int count, int flag)
{
int ret, rcnt= 0;
IsoStream *stream_pt;
stream_pt= (IsoStream *) stream;
while(rcnt<count) {
ret= iso_stream_read(stream_pt, (void *) (buf+rcnt), (size_t) (count-rcnt));
if(ret==0) /* EOF */
break;
if(ret<0) { /* error */
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", ret, "Error on read",
0, "FAILURE",1);
return(-1);
}
rcnt+= ret;
}
return(rcnt);
}
int Xorriso_iso_file_close(struct XorrisO *xorriso, void **stream, int flag)
{
int ret;
if(*stream==NULL)
return(0);
ret= iso_stream_close(*stream);
if(ret==1)
*stream= NULL;
Xorriso_process_msg_queues(xorriso,0);
return(ret);
}