/* 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, Provided under GPL version 2. */ #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------------ */ #ifndef Xorriso_standalonE /* The library which does the ISO 9660 / RockRidge manipulations */ #include /* The library which does MMC optical drive operations */ #include /* The library which enhances overwriteable media with ISO 9660 multi-session capabilities via the method invented by Andy Polyakov for growisofs */ #include /* 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 */ /* Some private in advance declarations */ int Xorriso_pacifier_loop(struct XorrisO *xorriso, struct burn_drive *drive, int flag); int Xorriso__read_pacifier(IsoImage *image, IsoFileSource *filesource); int Xorriso_tree_graft_node(struct XorrisO *xorriso, IsoImage *volume, IsoDir *dir, char *disk_path, char *img_name, char *nominal_source, char *nominal_target, off_t offset, off_t cut_size, IsoNode **node, int flag); int Xorriso_is_split(struct XorrisO *xorriso, IsoNode *node, int flag); #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, µ); 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) { int ret; ret= iso_sev_to_text(severity, severity_name); if(ret>0) return(ret); #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; ret= iso_text_to_sev(severity_name, severity_number); if(ret>0) return(ret); #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; xorriso->no_volset_present= 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; xorriso->no_volset_present= 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(hretin_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; xorriso->no_volset_present= 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; 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, µ); if(strlen(xorriso_id)<80) sprintf(xorriso_id+strlen(xorriso_id), ", LIBISOBURN-%d.%d.%d", major, minor, micro); iso_lib_version(&major, &minor, µ); if(strlen(xorriso_id)<80) sprintf(xorriso_id+strlen(xorriso_id), ", LIBISOFS-%d.%d.%d", major, minor, micro); burn_version(&major, &minor, µ); 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;} } isoburn_igopt_get_effective_lba(sopts, &(xorriso->session_lba)); ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0); if(ret<=0) goto ex; 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; } 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); xorriso->session_blocks= (int) (writecounter/ (off_t) 2048); sprintf(xorriso->info_text, "ISO image produced: %d sectors. Written to media: %d sectors at LBA %d\n", (int) (readcounter/ (off_t) 2048), xorriso->session_blocks, xorriso->session_lba); 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); if(!xorriso->no_volset_present) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); xorriso->no_volset_present= 1; return(0); } *volume= (IsoImage *) xorriso->in_volset_handle; xorriso->no_volset_present= 0; 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); } /* @param flag bit0= give directory x-permission where is r-permission */ int Xorriso_transfer_properties(struct XorrisO *xorriso, struct stat *stbuf, IsoNode *node, int flag) { mode_t mode; mode= stbuf->st_mode; if((flag&1) && S_ISDIR(mode)) { if(mode&S_IRUSR) mode|= S_IXUSR; if(mode&S_IRGRP) mode|= S_IXGRP; if(mode&S_IROTH) mode|= S_IXOTH; } iso_node_set_permissions(node, 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); } int Xorriso_graft_split(struct XorrisO *xorriso, IsoImage *volume, IsoDir *dir, char *disk_path, char *img_name, char *nominal_source, char *nominal_target, off_t size, IsoNode **node, int flag) { int ret; IsoDir *new_dir= NULL; IsoNode *part_node; int partno, total_parts; off_t offset; char part_name[SfileadrL], sfe[5*SfileadrL]; ret= iso_tree_add_new_dir(dir, img_name, &new_dir); if(ret<0) return(ret); *node= (IsoNode *) new_dir; total_parts= size / xorriso->split_size; if(size % xorriso->split_size) total_parts++; for(partno= 1; partno<=total_parts; partno++) { offset = xorriso->split_size * (off_t) (partno-1); Splitpart__compose(part_name, partno, total_parts, offset, xorriso->split_size, size, 0); ret= Xorriso_tree_graft_node(xorriso, volume, new_dir, disk_path, part_name, nominal_source, nominal_target, offset, xorriso->split_size, &part_node, 8); if(ret<=0) return(0); } sprintf(xorriso->info_text, "Split into %d parts: %s", total_parts, Text_shellsafe(nominal_target, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(1); } /* @param flag bit3= cut_out_node: offset and size are valid */ int Xorriso_tree_graft_node(struct XorrisO *xorriso, IsoImage *volume, IsoDir *dir, char *disk_path, char *img_name, char *nominal_source, char *nominal_target, off_t offset, off_t cut_size, IsoNode **node, int flag) { int ret; struct stat stbuf; char sfe[5*SfileadrL]; off_t size= 0; static off_t limit= ((off_t) 4) * ((off_t) 1024*1024*1024) - (off_t) 1; if(flag&8) { if(cut_size > limit) { sprintf(xorriso->info_text, "File piece exceeds size limit of %.f bytes: %.f from %s\n", (double) limit, (double) cut_size, Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } ret= iso_tree_add_new_cut_out_node(volume, dir, img_name, disk_path, offset, cut_size, node); if(ret<0) goto ex; } else { if(stat(disk_path, &stbuf)!=-1) if(S_ISREG(stbuf.st_mode)) size= stbuf.st_size; if(xorriso->split_size > 0 && size > xorriso->split_size) { ret= Xorriso_graft_split(xorriso, volume, dir, disk_path, img_name, nominal_source, nominal_target, size, node, 0); if(ret<=0) goto ex; return(1); } else if(size > limit) { sprintf(xorriso->info_text, "File exceeds size limit of %.f bytes: %s\n", (double) limit, Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } ret= iso_tree_add_new_node(volume, dir, img_name, disk_path, node); if(ret<0) goto ex; } ex:; if(ret<0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, nominal_source, ret, "Cannot add node to tree", 0, "FAILURE", 1|2); return(ret); } 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, target_is_split= 0; 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; } /* 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); target_is_split= 0; if(target_is_dir) target_is_split= Xorriso_is_split(xorriso, node, 0); if(!((target_is_dir && !target_is_split) && source_is_dir)) { Xorriso_process_msg_queues(xorriso,0); /* handle overwrite situation */; if(xorriso->do_overwrite==1 || (xorriso->do_overwrite==2 && !(target_is_dir && !target_is_split))) { ret= Xorriso_rmi(xorriso, NULL, (off_t) 0, 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= Xorriso_tree_graft_node(xorriso, volume, dir, srcpt, img_name, "", img_path, (off_t) 0, (off_t) 0, &node, 0); } } 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); } /* @param flag bit0= cut_out mode : base on leaf parent directory */ 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-(flag&1)-nic; if(d<0) return(-1); if(d>nfdc) return(0); for(i= 0; iinfo_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)); if(!((flag&1) && d==0)) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); return(1); } /* @param bit0= copy link target properties rather than link properties bit1= give directory x-permission where is r-permission */ 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, (flag&2)>>1); 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 bit3= use offset and cut_size for cut_out_node @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, off_t offset, off_t cut_size, 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; int target_is_split; 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; } 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); target_is_split= 0; if(target_is_dir) target_is_split= Xorriso_is_split(xorriso, node, 0); if(!((target_is_dir && !target_is_split) && source_is_dir)) { Xorriso_process_msg_queues(xorriso,0); /* handle overwrite situation */; if(xorriso->do_overwrite==1 || (xorriso->do_overwrite==2 && !(target_is_dir && !target_is_split))) { ret= Xorriso_rmi(xorriso, boss_iter, (off_t) 0, 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(disk_path!=NULL && !done) Xorriso_copy_implict_properties(xorriso, dir, img_path, path, disk_path, !!(flag&8)); } if(done) { attach_source:; 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= Xorriso_tree_graft_node(xorriso, volume, dir, disk_path_pt, apt, disk_path, img_path, offset, cut_size, &node, flag&8); if(ret<0) { 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); xorriso->pacifier_count++; if(xorriso->pacifier_count%100 && !(flag&2)) Xorriso_pacifier_callback(xorriso, "files added", xorriso->pacifier_count, xorriso->pacifier_total, "", 0); } } else *npt= '/'; } Xorriso_process_msg_queues(xorriso,0); return(1+!!is_dir); } /* @param flag bit0= -follow: disk_path is not a command parameter */ int Xorriso_cut_out(struct XorrisO *xorriso, char *disk_path, off_t startbyte, off_t bytecount, char *iso_rr_path, int flag) { int ret; char eff_source[SfileadrL], eff_dest[SfileadrL], sfe[SfileadrL*5]; struct stat stbuf; ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, disk_path, eff_source, 2|4); if(ret<=0) return(ret); if(lstat(eff_source, &stbuf)==-1) { Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-cut_out: Cannot determine type of %s", Text_shellsafe(eff_source, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); return(0); } if((stbuf.st_mode&S_IFMT) == S_IFLNK) { if(!(xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&1)))) goto unsupported_type; if(stat(eff_source, &stbuf)==-1) { Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-cut_out: Cannot determine link target type of %s", Text_shellsafe(eff_source, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); return(0); } } if(S_ISREG(stbuf.st_mode)) { if(stbuf.st_sizeinfo_text, "-cut_out: Byte offset %.f larger than file size %.f", (double) startbyte, (double) stbuf.st_size); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "SORRY", 0); return(0); } } else { unsupported_type:; Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-cut_out: Unsupported file type (%s) with %s", Ftypetxt(stbuf.st_mode, 0), Text_shellsafe(eff_source, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); return(0); } ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, iso_rr_path, eff_dest, 2|((flag&1)<<2)); if(ret<=0) return(ret); ret= Xorriso_graft_in(xorriso, NULL, eff_source, eff_dest, startbyte, bytecount, 8); return(ret); } 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]; off_t start_byte= 0; 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); ret= isoburn_get_min_start_byte(drive, &start_byte, 0); nwa= start_byte / 2048; if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); if(flag&1) 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_norequest_to_abort); session_no++) { tracks = burn_session_get_tracks(sessions[session_no], &num_tracks); if (tracks==NULL) continue; for(track_no= 0; track_norequest_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, ¤t_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, ¤t_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); } 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 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 bit5= with bit0 only remove directory content, not the directory @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, off_t boss_mem, 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; char *sfe= NULL, *sub_path= NULL; off_t mem; IsoNode **node_array= NULL; int node_count, node_idx; #ifdef Xorriso_fat_local_meM char sfe[5*SfileadrL], sub_path[2*SfileadrL]; #else /* 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) || (flag&32)) { /* Iterate over subordinates and delete them */ mem= boss_mem; ret= Xorriso_findi_iter(xorriso, (IsoDir *) victim_node, &mem, &iter, &node_array, &node_count, &node_idx, &node, 1|2); 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(1) { ret= Xorriso_findi_iter(xorriso, (IsoDir *) victim_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); 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, mem, 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(flag&32) {ret= 2; goto ex;} 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 */ Xorriso_findi_iter(xorriso, (IsoDir *) victim_node, &mem, &iter, &node_array, &node_count, &node_idx, &node, (1<<31)); 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 || irequest_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*1024result_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; jresult_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; iinfo_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; passrequest_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 bit3= just count nodes and return number */ 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); if(flag&8) {ret= filec; goto ex;} 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; irequest_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(ret); } /* @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; #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_rename() was requested to delete iterated node %s", Text_shellsafe(origin, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); return(-1); } #endif /* Libisofs_iso_dir_iter_sufficienT */ 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, (off_t) 0, 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, (off_t) 0, (off_t) 0, 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); } 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, "FAILURE", 1); return(-1); } Xorriso_process_msg_queues(xorriso,0); 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); } 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, (off_t) 0, (off_t) 0, 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; iwdi 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; iinfo_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 @return <=0 error, 1=ok 2=ok, node has been deleted, 3=ok, do not dive into directory (e.g. because it is a split file) */ 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, deleted= 0, no_dive= 0; 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, boss_mem, abs_path, hflag); deleted= 1; } } else if(action==2) { /* rm_r */ ret= Xorriso_rmi(xorriso, boss_iter, boss_mem, abs_path, 1|hflag); deleted= 1; } 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==2) deleted= 1; if(ret==3) no_dive= 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; } if(ret<=0) return(ret); if(deleted) return(2); if(no_dive) return(3); return(1); } /* @param flag bit0= recursion bit1= do not count deleted files with rm and rm_r @return <=0 error, 1= ok , 2= dir node and path has been deleted */ 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, deleted= 0, no_dive= 0; 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(ret==2) { deleted= 1; goto ex; } if(ret==3) no_dive= 1; } } if(no_dive || !LIBISO_ISDIR((IsoNode *) dir_node)) {ret= 1; 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; /* ??? This seems to be redundant with the single test above ??? Should i dive in unconditionally and leave out test and action here ? ??? Then do above test unconditionally ? --- Seems that the current configuration represents the special handling of the find start path with mount points. Dangerous to change. */ 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==2) /* node has been deleted */ continue; no_dive= (ret==3); if(ret<=0) { if(Xorriso_eval_problem_status(xorriso, ret, 1|2)<0) goto ex; } } if(S_ISDIR(stbuf.st_mode) && !no_dive) { 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); Xorriso_findi_iter(xorriso, dir_node, &mem, &iter, &node_array, &node_count, &node_idx, &node, (1<<31)); if(ret<=0) return(ret); if(deleted) return(2); return(1); } /* @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, µ); 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, µ); 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, µ); 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; /* for debugging #define Libisofs_lba_tesT yes */ #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>> ??? sort list ? */ for(i= 0; i<*count; i++) { /* >>> check for disjointness */; } memcpy(total_stbuf, &first_stbuf, sizeof(struct stat)); total_stbuf->st_size= total_bytes; ret= 1; ex:; if(iter!=NULL) iso_dir_iter_free(iter); return(ret); } int Xorriso_is_split(struct XorrisO *xorriso, IsoNode *node, int flag) { struct SplitparT *split_parts= NULL; int split_count= 0, ret; struct stat stbuf; ret= Xorriso_identify_split(xorriso, "", (void *) node, &split_parts, &split_count, &stbuf, 1); if(split_parts!=NULL) Splitparts_destroy(&split_parts, split_count, 0); return(ret>0); }