/* 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-2010 Thomas Schmitt, Provided under GPL version 2 or later. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for -charset */ #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_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 Xorriso__file_start_lba(IsoNode *node, int *lba, int flag); int Xorriso_read_file_data(struct XorrisO *xorriso, IsoNode *node, char *img_path, char *disk_path, off_t img_offset, off_t disk_offset, off_t bytes, int flag); int Xorriso_path_from_node(struct XorrisO *xorriso, IsoNode *in_node, char path[SfileadrL], int flag); int Xorriso_node_from_path(struct XorrisO *xorriso, IsoImage *volume, char *path, IsoNode **node, int flag); int Xorriso_path_from_lba(struct XorrisO *xorriso, IsoNode *node, int lba, char path[SfileadrL], int flag); int Xorriso__node_lba_cmp(const void *node1, const void *node2); int Xorriso_search_hardlinks(struct XorrisO *xorriso, IsoNode *node, int *node_idx, int *min_hl, int *max_hl, 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))) #define LIBISO_ISBOOT(node) (iso_node_get_type(node) == LIBISO_BOOT) /* CD specs say one shall not write tracks < 600 kiB */ #define Xorriso_cd_min_track_sizE 300 /* Default setting for -compliance */ #define Xorriso_relax_compliance_defaulT \ (isoburn_igopt_allow_deep_paths | isoburn_igopt_allow_longer_paths | \ isoburn_igopt_always_gmt | \ isoburn_igopt_rrip_version_1_10 | isoburn_igopt_aaip_susp_1_10 | \ isoburn_igopt_only_iso_versions | isoburn_igopt_no_j_force_dots) #ifdef NIX /* <<< */ unsigned long Xorriso_get_di_counteR= 0; #endif /* NIX */ /* ------------------------------------------------------------------------ */ static const char *un0(const char *text) { if(text == NULL) return(""); return(text); } int Xorriso_abort(struct XorrisO *xorriso, int flag) { int ret; ret= burn_abort(4440, burn_abort_pacifier, "xorriso : "); if(ret<=0) { fprintf(stderr, "\nxorriso : ABORT : Cannot cancel burn session and release drive.\n"); return(0); } fprintf(stderr, "xorriso : ABORT : Drive is released and library is shut down now.\n"); fprintf(stderr, "xorriso : ABORT : Program done. Even if you do not see a shell prompt.\n"); fprintf(stderr, "\n"); exit(1); } int Xorriso_destroy_node_array(struct XorrisO *xorriso, int flag) { int i; if(xorriso->node_array != NULL) { for(i= 0; i < xorriso->node_counter; i++) iso_node_unref((IsoNode *) xorriso->node_array[i]); free(xorriso->node_array); } xorriso->node_array= NULL; xorriso->node_counter= xorriso->node_array_size= 0; Xorriso_lst_destroy_all(&(xorriso->node_disk_prefixes), 0); Xorriso_lst_destroy_all(&(xorriso->node_img_prefixes), 0); return(1); } /* @param flag bit0= do not destroy hln_array but only hln_targets */ int Xorriso_destroy_hln_array(struct XorrisO *xorriso, int flag) { int i; if(xorriso->hln_array != NULL && !(flag & 1)) { for(i= 0; i < xorriso->hln_count; i++) iso_node_unref((IsoNode *) xorriso->hln_array[i]); free(xorriso->hln_array); xorriso->hln_array= NULL; xorriso->hln_count= 0; } if(xorriso->hln_targets != NULL) { for(i= 0; i < xorriso->hln_count; i++) if(xorriso->hln_targets[i] != NULL) free(xorriso->hln_targets[i]); free(xorriso->hln_targets); xorriso->hln_targets= NULL; } xorriso->node_targets_availmem= 0; return(1); } int Xorriso_destroy_di_array(struct XorrisO *xorriso, int flag) { int i; if(xorriso->di_array != NULL) { for(i= 0; i < xorriso->di_count; i++) if(xorriso->di_array[i] != NULL) iso_node_unref((IsoNode *) xorriso->di_array[i]); free(xorriso->di_array); xorriso->di_array= NULL; } if(xorriso->di_do_widen != NULL) { free(xorriso->di_do_widen); xorriso->di_do_widen= NULL; } Xorriso_lst_destroy_all(&(xorriso->di_disk_paths), 0); Xorriso_lst_destroy_all(&(xorriso->di_iso_paths), 0); xorriso->di_count= 0; #ifdef NIX /* <<< */ fprintf(stderr, "xorriso_DEBUG: get_di_count= %lu\n", Xorriso_get_di_counteR); #endif /* NIX */ return(1); } int Xorriso_new_node_array(struct XorrisO *xorriso, off_t mem_limit, int addon_nodes, int flag) { int i; if(xorriso->node_counter <= 0) return(1); xorriso->node_array= calloc(xorriso->node_counter + addon_nodes, sizeof(IsoNode *)); if(xorriso->node_array == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } for(i= 0; i < xorriso->node_counter + addon_nodes; i++) xorriso->node_array[i]= NULL; xorriso->node_array_size= xorriso->node_counter + addon_nodes; xorriso->node_counter= 0; return(1); } /* @param flag bit0= do not allocate hln_array but only hln_targets */ int Xorriso_new_hln_array(struct XorrisO *xorriso, off_t mem_limit, int flag) { int i; Xorriso_destroy_hln_array(xorriso, flag & 1); if(xorriso->hln_count <= 0) return(1); if(!(flag & 1)) { xorriso->hln_array= calloc(xorriso->hln_count, sizeof(char *)); if(xorriso->hln_array == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } for(i= 0; i < xorriso->hln_count; i++) xorriso->hln_array[i]= NULL; } xorriso->hln_targets= calloc(xorriso->hln_count, sizeof(char *)); if(xorriso->hln_targets == NULL) { if(!(flag & 1)) { free(xorriso->hln_array); xorriso->hln_array= NULL; } Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } for(i= 0; i < xorriso->hln_count; i++) xorriso->hln_targets[i]= NULL; xorriso->node_targets_availmem= mem_limit - xorriso->hln_count * sizeof(void *) - xorriso->hln_count * sizeof(char *); if(xorriso->node_targets_availmem < 0) xorriso->node_targets_availmem= 0; return(1); } int Xorriso__findi_sorted_ino_cmp(const void *p1, const void *p2) { int ret; IsoNode *n1, *n2; n1= *((IsoNode **) p1); n2= *((IsoNode **) p2); ret= Xorriso__node_lba_cmp(&n1, &n2); if(ret) return (ret > 0 ? 1 : -1); ret= iso_node_cmp_ino(n1, n2, 0); return(ret); } /* Not suitable for qsort() but for cross-array comparisons. p1 and p2 are actually IsoNode *p1, IsoNode *p2 */ int Xorriso__hln_cmp(const void *p1, const void *p2) { int ret; ret= Xorriso__findi_sorted_ino_cmp(&p1, &p2); if(ret) return (ret > 0 ? 1 : -1); if(p1 != p2) return(p1 < p2 ? -1 : 1); return(0); } /* p1 and p2 are actually IsoNode **p1, IsoNode **p2 */ int Xorriso__findi_sorted_cmp(const void *p1, const void *p2) { int ret; ret= Xorriso__findi_sorted_ino_cmp(p1, p2); if(ret) return (ret > 0 ? 1 : -1); if(p1 != p2) return(p1 < p2 ? -1 : 1); return(0); } int Xorriso_sort_node_array(struct XorrisO *xorriso, int flag) { if(xorriso->node_counter <= 0) return(0); qsort(xorriso->node_array, xorriso->node_counter, sizeof(IsoNode *), Xorriso__findi_sorted_cmp); return(1); } int Xorriso__search_node(void *node_array[], int n, int (*cmp)(const void *p1, const void *p2), void *node, int *idx, int flag) { int ret, l, r, p, pos; if(n == 0) return(0); l= 0; r= n + 1; while(1) { p= (r - l) / 2; if(p == 0) break; p+= l; /* NULL elements may indicate invalid nodes. Their first valid right neigbor will serve as proxy. If none exists, then the test pushes leftwards. */ for(pos= p - 1; pos < n; pos++) if(node_array[pos] != NULL) break; if(pos < n) ret= (*cmp)(&(node_array[pos]), &node); else ret= 1; if(ret < 0) l= p; else if(ret > 0) r= p; else { *idx= pos; return(1); } } return(0); } int Xorriso_search_in_hln_array(struct XorrisO *xorriso, void *node, int *idx, int flag) { int ret; if(xorriso->hln_array == NULL || xorriso->hln_count <= 0) return(0); ret= Xorriso__search_node(xorriso->hln_array, xorriso->hln_count, Xorriso__findi_sorted_ino_cmp, node, idx, 0); return ret; } int Xorriso__get_di(IsoNode *node, dev_t *dev, ino_t *ino, int flag) { int ret, i, i_end, imgid, error_code; size_t value_length= 0; char *value= NULL, msg[ISO_MSGS_MESSAGE_LEN], severity[80]; unsigned char *vpt; static char *name= "isofs.di"; #ifdef NIX /* <<< */ Xorriso_get_di_counteR++; #endif /* NIX */ *dev= 0; *ino= 0; ret= iso_node_lookup_attr(node, name, &value_length, &value, 0); if(ret <= 0) { /* Drop any pending messages because there is no xorriso to take them */ iso_obtain_msgs("NEVER", &error_code, &imgid, msg, severity); return(ret); } vpt= (unsigned char *) value; for(i= 1; i <= vpt[0] && i < value_length; i++) *dev= ((*dev) << 8) | vpt[i]; i_end= i + vpt[i] + 1; for(i++; i < i_end && i < value_length; i++) *ino= ((*ino) << 8) | vpt[i]; free(value); return(1); } int Xorriso__di_ino_cmp(const void *p1, const void *p2) { int ret; IsoNode *n1, *n2; dev_t d1, d2; ino_t i1, i2; n1= *((IsoNode **) p1); n2= *((IsoNode **) p2); ret= Xorriso__get_di(n1, &d1, &i1, 0); if(ret <= 0) {d1= 0; i1= 0;} ret= Xorriso__get_di(n2, &d2, &i2, 0); if(ret <= 0) {d2= 0; i2= 0;} if(d1 < d2) return(-1); if(d1 > d2) return(1); if(i1 < i2) return(-1); if(i1 > i2) return(1); if(d1 == 0 && i1 == 0 && n1 != n2) return(n1 < n2 ? -1 : 1); return(0); } int Xorriso__di_cmp(const void *p1, const void *p2) { int ret; IsoNode *n1, *n2; ret= Xorriso__di_ino_cmp(p1, p2); if(ret) return(ret); n1= *((IsoNode **) p1); n2= *((IsoNode **) p2); if(n1 != n2) return(n1 < n2 ? -1 : 1); return(0); } int Xorriso__sort_di(void *node_array[], int count, int flag) { if(count <= 0) return(0); qsort(node_array, count, sizeof(IsoNode *), Xorriso__di_cmp); return(1); } int Xorriso_invalidate_di_item(struct XorrisO *xorriso, IsoNode *node, int flag) { int ret, idx; if(xorriso->di_array == NULL) return(1); ret= Xorriso__search_node(xorriso->di_array, xorriso->di_count, Xorriso__di_cmp, node, &idx, 0); if(ret <= 0) return(ret == 0); if(xorriso->di_array[idx] != NULL) iso_node_unref(xorriso->di_array[idx]); xorriso->di_array[idx]= NULL; return(1); } /* @param flag bit0= return 1 even if matching nodes were found but node is not among them bit1= use Xorriso__di_cmp() rather than Xorriso__di_ino_cmp() */ int Xorriso_search_di_range(struct XorrisO *xorriso, IsoNode *node, int *idx, int *low, int *high, int flag) { int ret, i, found; int (*cmp)(const void *p1, const void *p2)= Xorriso__di_ino_cmp; if(flag & 2) cmp= Xorriso__di_cmp; *high= *low= *idx= -1; ret= Xorriso__search_node(xorriso->di_array, xorriso->di_count, cmp, node, &found, 0); if(ret <= 0) return(0); *low= *high= found; for(i= found + 1; i < xorriso->di_count; i++) if(xorriso->di_array[i] != NULL) { if((*cmp)(&node, &(xorriso->di_array[i])) != 0) break; *high= i; } for(i= found - 1; i >= 0; i--) if(xorriso->di_array[i] != NULL) { if((*cmp)(&node, &(xorriso->di_array[i])) != 0) break; *low= i; } for(i= *low; i <= *high; i++) if(xorriso->di_array[i] == node) { *idx= i; break; } return(*idx >= 0 || (flag & 1)); } /* ------------------------------------------------------------------------ */ /* @param flag bit0= asynchronous handling (else catch thread, wait, and exit) */ int Xorriso_set_signal_handling(struct XorrisO *xorriso, int flag) { char *handler_prefix= NULL; if(Xorriso__get_signal_behavior(0) != 1) return(2); handler_prefix= calloc(strlen(xorriso->progname)+3+1, 1); if(handler_prefix==NULL) { sprintf(xorriso->info_text, "Cannot allocate memory for for setting signal handler"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); return(-1); } sprintf(handler_prefix, "%s : ", xorriso->progname); burn_set_signal_handling(handler_prefix, NULL, (flag & 1) * 0x30); free(handler_prefix); return(1); } int Xorriso_startup_libraries(struct XorrisO *xorriso, int flag) { int ret, major, minor, micro; char *queue_sev, *print_sev, reason[1024]; struct iso_zisofs_ctrl zisofs_ctrl= {0, 6, 15}; /* 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) */ 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); 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()); */ isoburn_set_msgs_submit(Xorriso_msgs_submit_void, (void *) xorriso, (3<<2) | 128 , 0); ret= Xorriso_set_signal_handling(xorriso, 0); if(ret <= 0) return(ret); ret = iso_zisofs_get_params(&zisofs_ctrl, 0); if (ret == 1) { xorriso->zisofs_block_size= xorriso->zisofs_block_size_default= (1 << zisofs_ctrl.block_size_log2); xorriso->zlib_level= xorriso->zlib_level_default= zisofs_ctrl.compression_level; } 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); } strcpy(xorriso->info_text, "Using "); strncat(xorriso->info_text, burn_scsi_transport_id(0), 1024); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); 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; Sectorbitmap_destroy(&(xorriso->in_sector_map), 0); Xorriso_destroy_di_array(xorriso, 0); Xorriso_destroy_hln_array(xorriso, 0); } if(flag&1) { if(xorriso->libs_are_started==0) return(0); isoburn_finish(); } return(1); } /* @param flag bit0= if not MMC drive print NOTE and return 2 bit1= obtain outdrive, else indrive bit4= do not report failure */ int Xorriso_get_drive_handles(struct XorrisO *xorriso, struct burn_drive_info **dinfo, struct burn_drive **drive, char *attempt, int flag) { int ret; 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 && !(flag & 16)) { 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); } if(*dinfo==NULL) return(0); *drive= (*dinfo)[0].drive; if(flag & 1) { ret= burn_drive_get_drive_role(*drive); if(ret != 1) { sprintf(xorriso->info_text, "Output device is not an MMC drive. Desired operation does not apply."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(2); } } return((*drive)!=NULL); } 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); ret= burn_sev_to_text(severity, severity_name, 0); if(ret>0) return(ret); *severity_name= ""; return(0); } 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); ret= burn_text_to_sev(severity_name, severity_number, 0); return(ret); } /* @param flag bit0= report libisofs error text bit1= victim is disk_path bit2= do not inquire libisofs, report msg_text and min_severity */ 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); if(flag&4) { error_code= 0x00050000; Xorriso__text_to_sev(min_severity, &iso_sev, 0); } else { 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); iso_sev= iso_error_get_severity(iso_error_code); } if(msg_text_pt==NULL) msg_text_pt= msg_text; 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 && !(flag&4)) 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; Sectorbitmap_destroy(&(xorriso->in_sector_map), 0); Xorriso_destroy_di_array(xorriso, 0); Xorriso_destroy_hln_array(xorriso, 0); xorriso->loaded_volid[0]= 0; xorriso->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, xorriso->in_charset); 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->in_sector_map= NULL; Xorriso_update_volid(xorriso, 0); xorriso->volset_change_pending= 0; xorriso->no_volset_present= 0; return(1); } int Xorriso_record_boot_info(struct XorrisO *xorriso, int flag) { int ret; struct burn_drive_info *dinfo; struct burn_drive *drive; IsoImage *image; ElToritoBootImage *bootimg; IsoFile *bootimg_node; IsoBoot *bootcat_node; xorriso->loaded_boot_bin_lba= -1; xorriso->loaded_boot_cat_path[0]= 0; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to record boot LBAs", 0); if(ret<=0) return(0); image= isoburn_get_attached_image(drive); if(image == NULL) return(0); ret= iso_image_get_boot_image(image, &bootimg, &bootimg_node, &bootcat_node); iso_image_unref(image); /* release obtained reference */ if(ret != 1) return(0); if(bootimg_node != NULL) Xorriso__file_start_lba((IsoNode *) bootimg_node, &(xorriso->loaded_boot_bin_lba), 0); if(bootcat_node != NULL) Xorriso_path_from_lba(xorriso, (IsoNode *) bootcat_node, 0, xorriso->loaded_boot_cat_path, 0); return(1); } int Xorriso_assert_volid(struct XorrisO *xorriso, int msc1, int flag) { int ret, image_blocks; char volid[33]; struct burn_drive_info *dinfo; struct burn_drive *drive; if(xorriso->assert_volid[0] == 0) return(1); ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to perform -assert_volid", 0); if(ret<=0) return(0); ret= isoburn_read_iso_head(drive, msc1, &image_blocks, volid, 1); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) { sprintf(xorriso->info_text, "-assert_volid: Cannot determine Volume Id at LBA %d.", msc1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, xorriso->assert_volid_sev, 0); return(0); } ret= Sregex_match(xorriso->assert_volid, volid, 0); if(ret < 0) return(2); if(ret == 0) { strcpy(xorriso->info_text, "-assert_volid: Volume id does not match pattern: "); Text_shellsafe(xorriso->assert_volid, xorriso->info_text, 1); strcat(xorriso->info_text, " <> "); Text_shellsafe(volid, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, xorriso->assert_volid_sev, 0); return(0); } return(ret); } /* @param flag bit0= aquire as isoburn input drive bit1= aquire as libburn output drive (as isoburn drive if bit0) bit2= regard overwriteable media as blank bit3= if the drive is a regular disk file: truncate it to the write start address bit5= do not print toc bit6= do not calm down drive after aquiring it @return <=0 failure , 1= ok 2=success, but not writeable with bit1 3=success, but not blank and not ISO with bit0 */ int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag) { int ret, hret, not_writeable= 0, has_what, aquire_flag, load_lba, ext; int lba, track, session, params_flag, adr_mode, read_ret; uint32_t size; struct burn_drive_info *dinfo= NULL, *out_dinfo, *in_dinfo; struct burn_drive *drive= NULL, *out_drive, *in_drive; enum burn_disc_status state; IsoImage *volset = NULL; IsoNode *root_node; struct isoburn_read_opts *ropts= NULL; char libburn_adr[SfileadrL], *boot_fate, *sev; size_t value_length; char *value= NULL; double num; char volid[33], adr_data[163], *adr_pt; if((flag&3)==0) { sprintf(xorriso->info_text, "XORRISOBURN program error : Xorriso_aquire_drive bit0+bit1 not set"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); return(-1); } ret= Xorriso_give_up_drive(xorriso, (flag&3)|8); if(ret<=0) return(ret); if(flag & 1) xorriso->isofs_st_out= time(0) - 1; ret= Xorriso_auto_driveadr(xorriso, adr, libburn_adr, 0); if(ret <= 0) return(ret); if(strcmp(libburn_adr,"stdio:/dev/fd/1")==0) { if(xorriso->dev_fd_1<0) { sprintf(xorriso->info_text, "-*dev \"stdio:/dev/fd/1\" was not a start argument. Cannot use it now."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } else { sprintf(libburn_adr, "stdio:/dev/fd/%d", xorriso->dev_fd_1); } } if((flag&3)==1 && xorriso->out_drive_handle!=NULL) { ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive, "on attempt to compare new indev with outdev", 2); if(ret<=0) goto ex; ret= burn_drive_equals_adr(out_drive, libburn_adr, 1); if(ret==1) { dinfo= out_dinfo; xorriso->indev_is_exclusive= xorriso->outdev_is_exclusive; } } else if((flag&3)==2 && xorriso->in_drive_handle!=NULL) { ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive, "on attempt to compare new outdev with indev", 0); if(ret<=0) goto ex; ret= burn_drive_equals_adr(in_drive, libburn_adr, 1); if(ret==1) { dinfo= in_dinfo; xorriso->outdev_is_exclusive= xorriso->indev_is_exclusive; } } if(dinfo==NULL) { aquire_flag= 1 | ((flag&(8|4))>>1) | ((xorriso->toc_emulation_flag & 3)<<3); if(xorriso->toc_emulation_flag & 4) aquire_flag|= 128; if(!(xorriso->do_aaip & 1)) aquire_flag|= 32; if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (4 | 32))) aquire_flag|= 64; burn_preset_device_open(xorriso->drives_exclusive, 0, 0); ret= isoburn_drive_aquire(&dinfo, libburn_adr, aquire_flag); burn_preset_device_open(1, 0, 0); Xorriso_process_msg_queues(xorriso,0); if(ret<=0) { sprintf(xorriso->info_text,"Cannot aquire drive '%s'", adr); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } if(flag&1) if(xorriso->image_start_mode&(1<<31)) /* used up setting */ xorriso->image_start_mode= 0; /* no need to perform auto setting */ if(flag & 1) xorriso->indev_is_exclusive= xorriso->drives_exclusive; if(flag & 2) xorriso->outdev_is_exclusive= xorriso->drives_exclusive; } drive= dinfo[0].drive; if(flag&1) { if(xorriso->image_start_mode&(1<<31)) /* used up setting */ xorriso->image_start_mode&= ~0xffff; /* perform auto setting */ if((xorriso->image_start_mode&(1<<30))) { /* if enabled at all */ adr_pt= xorriso->image_start_value; adr_mode= xorriso->image_start_mode & 0xffff; if(adr_mode == 4 && strlen(adr_pt) <= 80) { /* Convert volid search expression into lba */ params_flag= 0; ret= Xorriso__bourne_to_reg(xorriso->image_start_value, adr_data, 0); if(ret == 1) params_flag|= 4; ret= isoburn_get_mount_params(drive, 4, adr_data, &lba, &track, &session, volid, params_flag); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) goto ex; if(session <= 0 || track <= 0 || ret == 2) { Xorriso_msgs_submit(xorriso, 0, "-load : Given address does not point to an ISO 9660 session", 0, "FAILURE", 0); ret= 0; goto ex; } sprintf(volid, "%d", lba); adr_pt= volid; adr_mode= 3; } ret= isoburn_set_msc1(drive, adr_mode, adr_pt, !!(xorriso->image_start_mode & (1<<16))); if(ret<=0) goto ex; if(xorriso->image_start_mode&(1<<31)) xorriso->image_start_mode= 0; /* disable msc1 setting completely */ else xorriso->image_start_mode|= (1<<31); /* mark as used up */ } } state= isoburn_disc_get_status(drive); Xorriso_process_msg_queues(xorriso,0); if(flag&1) { volset= isoburn_get_attached_image(drive); if(volset != NULL) { /* The image object is already created */ iso_image_unref(volset); } } if(flag&2) { xorriso->out_drive_handle= dinfo; if(Sfile_str(xorriso->outdev, adr, 0)<=0) {ret= -1; goto ex;} if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE) { sprintf(xorriso->info_text, "Disc status unsuitable for writing"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); not_writeable= 1; } } if(flag&1) { xorriso->in_drive_handle= dinfo; if(Sfile_str(xorriso->indev, adr, 0)<=0) {ret= -1; goto ex;} } else if(flag&2) { if(xorriso->in_volset_handle==NULL) { /* No volume loaded: create empty one */ ret= Xorriso_create_empty_iso(xorriso, 0); if(ret<=0) goto ex; } else { iso_image_ref((IsoImage *) xorriso->in_volset_handle); ret= isoburn_attach_image(drive, (IsoImage *) xorriso->in_volset_handle); if(ret<=0) { sprintf(xorriso->info_text, "Failed to attach ISO image object to outdev"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); {ret= -1; goto ex;} } } if(!(flag&32)) Xorriso_toc(xorriso, 1 | 2 | 8); {ret= 1+not_writeable; goto ex;} } if(xorriso->in_volset_handle!=NULL) iso_image_unref((IsoImage *) xorriso->in_volset_handle); xorriso->in_volset_handle= NULL; Sectorbitmap_destroy(&(xorriso->in_sector_map), 0); Xorriso_destroy_hln_array(xorriso, 0); Xorriso_destroy_di_array(xorriso, 0); /* check for invalid state */ if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE && state != BURN_DISC_FULL) { sprintf(xorriso->info_text, "Disc status not blank and unsuitable for reading"); sev= "FAILURE"; if(xorriso->img_read_error_mode==2) sev= "FATAL"; Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0); Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2)); ret= 3; goto ex; } /* fill read opts */ ret= isoburn_ropt_new(&ropts, 0); if(ret<=0) goto ex; ext= isoburn_ropt_noiso1999; if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (1 | 4 | 32)) && !(xorriso->do_md5 & 1)) ext|= isoburn_ropt_noaaip; if(!(xorriso->do_aaip & 1)) ext|= isoburn_ropt_noacl; if(!(xorriso->do_aaip & 4)) ext|= isoburn_ropt_noea; if(xorriso->ino_behavior & 1) ext|= isoburn_ropt_noino; #ifdef isoburn_ropt_nomd5 if(!(xorriso->do_md5 & 1)) ext|= isoburn_ropt_nomd5; #endif isoburn_ropt_set_extensions(ropts, ext); isoburn_ropt_set_default_perms(ropts, (uid_t) 0, (gid_t) 0, (mode_t) 0555); isoburn_ropt_set_input_charset(ropts, xorriso->in_charset); isoburn_ropt_set_auto_incharset(ropts, !!(xorriso->do_aaip & 512)); Xorriso_set_image_severities(xorriso, 1); /* No DEBUG messages */ Xorriso_pacifier_reset(xorriso, 0); isoburn_set_read_pacifier(drive, Xorriso__read_pacifier, (void *) xorriso); /* <<< Trying to work around too much tolerance on bad image trees. Better would be a chance to instruct libisofs what to do in case of image read errors. There is a risk to mistake other SORRYs. */ if(xorriso->img_read_error_mode>0) iso_set_abort_severity("SORRY"); if(state != BURN_DISC_BLANK) { ret= isoburn_disc_get_msc1(drive, &load_lba); if(ret > 0) { sprintf(xorriso->info_text, "Loading ISO image tree from LBA %d", load_lba); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); } ret= Xorriso_assert_volid(xorriso, load_lba, 0); if(ret <= 0) goto ex; } read_ret= ret= isoburn_read_image(drive, ropts, &volset); /* <<< Resetting to normal thresholds */ if(xorriso->img_read_error_mode>0) Xorriso_set_abort_severity(xorriso, 0); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_set_image_severities(xorriso, 0); Xorriso_give_up_drive(xorriso, 1|((flag&32)>>2)); sprintf(xorriso->info_text,"Cannot read ISO image tree"); sev= "FAILURE"; if(xorriso->img_read_error_mode==2) sev= "FATAL"; Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev, 0); if(read_ret == ISO_SB_TREE_CORRUPTED && (xorriso->do_md5 & 1)) { Xorriso_msgs_submit(xorriso, 0, "You might get a questionable ISO image tree by option -md5 'off'.", 0, "HINT", 0); } else if(xorriso->img_read_error_mode!=0) { Xorriso_msgs_submit(xorriso, 0, "You might get a partial or altered ISO image tree by option -error_behavior 'image_loading' 'best_effort' if -abort_on is set to be tolerant enough.", 0, "HINT", 0); } ret= 3; goto ex; } Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0, "", 1); /* report end count */ xorriso->in_volset_handle= (void *) volset; xorriso->in_sector_map= NULL; Xorriso_set_image_severities(xorriso, 0); Xorriso_update_volid(xorriso, 0); strncpy(xorriso->application_id, un0(iso_image_get_application_id(volset)), 128); xorriso->application_id[128]= 0; strncpy(xorriso->publisher, un0(iso_image_get_publisher_id(volset)), 128); xorriso->publisher[128]= 0; strncpy(xorriso->system_id, un0(iso_image_get_system_id(volset)), 32); xorriso->system_id[32]= 0; strncpy(xorriso->volset_id, un0(iso_image_get_volset_id(volset)), 128); xorriso->volset_id[128]= 0; /* <<< can be removed as soon as libisofs-0.6.24 is mandatory */ if(strcmp(un0(iso_image_get_copyright_file_id(volset)), "_") == 0 && strcmp(un0(iso_image_get_abstract_file_id(volset)), "_") == 0 && strcmp(un0(iso_image_get_biblio_file_id(volset)), "_") == 0) { /* This is bug output from libisofs <= 0.6.23 . The texts mean file names and should have been empty to indicate that there are no such files. It is obvious that not all three roles can be fulfilled by one file "_" so that one cannot spoil anything by assuming them empty now. Modern versions of libisofs are supposed to do this themselves. */ iso_image_set_copyright_file_id(volset, ""); iso_image_set_abstract_file_id(volset, ""); iso_image_set_biblio_file_id(volset, ""); } if(xorriso->out_drive_handle != NULL && xorriso->out_drive_handle != xorriso->in_drive_handle) { ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive, "on attempt to attach ISO image volset to outdev", 2); if(ret<=0) goto ex; iso_image_ref((IsoImage *) xorriso->in_volset_handle); isoburn_attach_image(out_drive, xorriso->in_volset_handle); } Xorriso_process_msg_queues(xorriso,0); isoburn_ropt_get_size_what(ropts, &size, &has_what); if(has_what & isoburn_ropt_has_el_torito) { if(xorriso->boot_image_bin_path[0]) boot_fate= "replaced by new boot image"; else if(xorriso->patch_isolinux_image) boot_fate= "patched at boot info table"; else if(xorriso->keep_boot_image) boot_fate= "kept unchanged"; else boot_fate= "discarded"; sprintf(xorriso->info_text, "Detected El-Torito boot information which currently is set to be %s", boot_fate); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); Xorriso_record_boot_info(xorriso, 0); } if(flag & 1) { /* Look for isofs.st and put it into xorriso->isofs_st_in */; root_node= (IsoNode *) iso_image_get_root(volset); ret= iso_node_lookup_attr(root_node, "isofs.st", &value_length, &value, 0); if(ret > 0) { if(value_length > 0) { sscanf(value, "%lf", &num); if(num > 0) xorriso->isofs_st_in= num; } free(value); } } if(!(flag&32)) { Xorriso_toc(xorriso, 1 | 8); if(xorriso->loaded_volid[0]!=0) { sprintf(xorriso->info_text,"Volume id : '%s'\n", xorriso->loaded_volid); Xorriso_info(xorriso, 0); if(strcmp(xorriso->loaded_volid, xorriso->volid) != 0 && !xorriso->volid_default) { sprintf(xorriso->info_text, "New volume id: '%s'\n", xorriso->volid); Xorriso_info(xorriso, 0); } } } ret= 1+not_writeable; ex: Xorriso_process_msg_queues(xorriso,0); if(ret<=0) { hret= Xorriso_give_up_drive(xorriso, (flag&3)|((flag&32)>>2)); if(hretdo_calm_drive & 1) && !(flag & 64)) burn_drive_snooze(drive, 0); /* No need to make noise from start */ } if(ropts!=NULL) isoburn_ropt_destroy(&ropts, 0); return(ret); } /* @param flag bit0=input drive bit1=output drive bit2=eject bit3=no info message or toc */ int Xorriso_give_up_drive(struct XorrisO *xorriso, int flag) { int in_is_out_too, ret, do_eject; struct burn_drive_info *dinfo; struct burn_drive *drive; char sfe[5*SfileadrL]; in_is_out_too= (xorriso->in_drive_handle == xorriso->out_drive_handle); if((flag&4) && in_is_out_too && (flag&(1|2))) { if((flag&3)!=3) { sprintf(xorriso->info_text,"Giving up for -eject whole -dev %s", Text_shellsafe(xorriso->indev, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); } flag|= 3; /* give up in/out drive to eject it */ } if((flag&1) && xorriso->in_drive_handle != NULL) { Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to give up drive", 0); if(!in_is_out_too) { do_eject= !!(flag&4); if((flag & 4) && !xorriso->indev_is_exclusive) { sprintf(xorriso->info_text, "Will not eject media in non-exclusively aquired input drive."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); do_eject= 0; } if(drive!=NULL) isoburn_drive_release(drive, do_eject); if(dinfo!=NULL) burn_drive_info_free(dinfo); } xorriso->in_drive_handle= NULL; xorriso->indev[0]= 0; if(xorriso->in_volset_handle!=NULL) iso_image_unref((IsoImage *) xorriso->in_volset_handle); xorriso->in_volset_handle= NULL; Sectorbitmap_destroy(&(xorriso->in_sector_map), 0); Xorriso_destroy_di_array(xorriso, 0); Xorriso_destroy_hln_array(xorriso, 0); xorriso->loaded_volid[0]= 0; xorriso->isofs_st_out= time(0) - 1; xorriso->isofs_st_in= 0; xorriso->volset_change_pending= 0; xorriso->no_volset_present= 0; xorriso->loaded_boot_bin_lba= 0; xorriso->loaded_boot_cat_path[0]= 0; in_is_out_too= 0; } if((flag&2) && xorriso->out_drive_handle!=NULL) { do_eject= !!(flag&4); if((flag & 4) && !xorriso->outdev_is_exclusive) { sprintf(xorriso->info_text, "Will not eject media in non-exclusively aquired drive."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); do_eject= 0; } Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to give up drive", 2); if(!in_is_out_too) { if(drive!=NULL) isoburn_drive_release(drive, do_eject); if(dinfo!=NULL) burn_drive_info_free(dinfo); } xorriso->out_drive_handle= NULL; xorriso->outdev[0]= 0; } else if((flag&1) && xorriso->out_drive_handle!=NULL) { ret= Xorriso_create_empty_iso(xorriso, 0); if(ret<=0) return(ret); if(!(flag&8)) { sprintf(xorriso->info_text, "Only the output drive remains. Created empty ISO image.\n"); Xorriso_info(xorriso, 0); Xorriso_toc(xorriso, 1 | 2 | 8); } } Xorriso_process_msg_queues(xorriso,0); return(1); } int Xorriso_make_write_options( struct XorrisO *xorriso, struct burn_drive *drive, struct burn_write_opts **burn_options, int flag) { int drive_role, stream_mode= 0; *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); if(xorriso->do_stream_recording == 1) stream_mode= 1; else if(xorriso->do_stream_recording == 2) stream_mode= 51200; /* 100 MB */ else if(xorriso->do_stream_recording >= 16) stream_mode= xorriso->do_stream_recording; burn_write_opts_set_stream_recording(*burn_options, stream_mode); #ifdef Xorriso_dvd_obs_default_64K if(xorriso->dvd_obs == 0) burn_write_opts_set_dvd_obs(*burn_options, 64 * 1024); else #endif burn_write_opts_set_dvd_obs(*burn_options, xorriso->dvd_obs); burn_write_opts_set_stdio_fsync(*burn_options, xorriso->stdio_sync); 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, lba, nwa; 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 && ret>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); } } if(xorriso->alignment == 0) { ret= isoburn_needs_emulation(drive); if(ret > 0) { /* Take care that the session is padded up to the future NWA. Else with padding < 32 it could happen that PVDs from older sessions survive and confuse -rom_toc_scan. */ xorriso->alignment= 32; } } if(xorriso->alignment > 0) { if(img_sectors > 0) { ret= isoburn_disc_track_lba_nwa(drive, burn_options, 0, &lba, &nwa); if(ret <= 0) nwa= 0; lba= (nwa + img_sectors + padding) % xorriso->alignment; if(lba > 0) padding+= xorriso->alignment - lba; } else if(padding < xorriso->alignment) padding= xorriso->alignment; } 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); } /* @return <0 yes , 0 no , <0 error */ int Xorriso_is_isohybrid(struct XorrisO *xorriso, IsoFile *bootimg_node, int flag) { int ret; unsigned char buf[68]; void *data_stream= NULL; ret= Xorriso_iso_file_open(xorriso, "", (void *) bootimg_node, &data_stream, 1); if(ret <= 0) return(-1); ret= Xorriso_iso_file_read(xorriso, data_stream, (char *) buf, 68, 0); Xorriso_iso_file_close(xorriso, &data_stream, 0); if(ret <= 0) return(0); if(buf[64] == 0xfb && buf[65] == 0xc0 && buf[66] == 0x78 && buf[67] == 0x70) return(1); return(0); } int Xorriso_set_isolinux_options(struct XorrisO *xorriso, IsoImage *image, int flag) { int make_isohybrid_mbr= 0, ret, patch_table= 0; ElToritoBootImage *bootimg; IsoFile *bootimg_node; ret= iso_image_get_boot_image(image, &bootimg, &bootimg_node, NULL); if(ret != 1) { sprintf(xorriso->info_text, "Programming error: No boot image available in Xorriso_set_isolinux_options()"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); return(-1); } patch_table = !!xorriso->patch_isolinux_image; if(xorriso->boot_image_isohybrid == 0) { ret= el_torito_set_isolinux_options(bootimg, patch_table, 0); return(ret == 1); } if(xorriso->boot_image_isohybrid == 3) { make_isohybrid_mbr= 1; } else { ret= Xorriso_is_isohybrid(xorriso, bootimg_node, 0); if(ret < 0) return(0); if(ret > 0) make_isohybrid_mbr= 1; } if(xorriso->boot_image_isohybrid == 2 && !make_isohybrid_mbr) { sprintf(xorriso->info_text, "Isohybrid signature is demanded but not found in boot image file."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } if(make_isohybrid_mbr) { sprintf(xorriso->info_text, "Will write isohybrid MBR."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); xorriso->alignment= 512; } ret= el_torito_set_isolinux_options(bootimg, patch_table | (make_isohybrid_mbr << 1),0); return(ret == 1); } int Xorriso_auto_format(struct XorrisO *xorriso, int flag) { int ret, profile, status, num_formats; char profile_name[80]; struct burn_drive_info *dinfo; struct burn_drive *drive; off_t size; unsigned dummy; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to autoformat", 2); if(ret<=0) return(0); ret= burn_disc_get_profile(drive, &profile, profile_name); if(ret>0 && (profile==0x12 || profile==0x43)) { /* DVD-RAM or BD-RE */ ret= burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats); if(ret>0 && status==BURN_FORMAT_IS_UNFORMATTED) { sprintf(xorriso->info_text, "Unformatted %s media detected. Trying -format fast.", profile_name); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= Xorriso_format_media(xorriso, (off_t) 0, 1 | 4); if(ret<=0) { sprintf(xorriso->info_text, "Automatic formatting of %s failed", profile_name); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(ret); } } } return(1); } int Xorriso_set_system_area(struct XorrisO *xorriso, struct burn_drive *drive, IsoImage *img, struct isoburn_imgen_opts *sopts, int flag) { int ret, options, system_area_options, iso_lba= 0; int num_sessions= 0, num_tracks= 0, start_lba, end_lba, image_blocks; char volid[33]; FILE *fp= NULL; char buf[32768], *bufpt= NULL; off_t hd_lba; unsigned char *ub; ElToritoBootImage *bootimg; IsoFile *bootimg_node; struct isoburn_toc_disc *disc= NULL; struct isoburn_toc_session **sessions; struct isoburn_toc_track **tracks; struct burn_toc_entry toc_entry; system_area_options= xorriso->system_area_options; memset(buf, 0, 32768); if(xorriso->system_area_disk_path[0] == 0) { if(xorriso->patch_system_area) { ret= iso_image_get_system_area(img, buf, &options, 0); if(ret == 0) { goto do_set; } else if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", ret, "Error when inquiring System Area data of ISO 9660 image", 0, "FAILURE", 1); {ret= 0; goto ex;} } else { system_area_options= xorriso->patch_system_area; /* Check whether partition 1 ends at image end */; ub= (unsigned char *) buf; hd_lba= (ub[454] | (ub[455] << 8) | (ub[456] << 16) | (ub[457] << 24)) + (ub[458] | (ub[459] << 8) | (ub[460] << 16) | (ub[461] << 24)); disc= isoburn_toc_drive_get_disc(drive); if(disc == NULL) iso_lba= -1; else { /* With sequential media this is the track end, not the ISO size */ end_lba= isoburn_toc_disc_get_sectors(disc); /* So inquire start and ISO size of the last track */ iso_lba= -1; sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions); if(num_sessions > 0) tracks= isoburn_toc_session_get_tracks(sessions[num_sessions - 1], &num_tracks); if(tracks != NULL && num_tracks > 0) isoburn_toc_track_get_entry(tracks[num_tracks - 1], &toc_entry); if (toc_entry.extensions_valid & 1) { ret= isoburn_toc_track_get_emul(tracks[num_tracks - 1], &start_lba, &image_blocks, volid, 0); if(ret > 0) { iso_lba= start_lba + image_blocks; } else { start_lba= toc_entry.start_lba; ret= isoburn_read_iso_head(drive, start_lba, &image_blocks, volid, 1); if(ret > 0) iso_lba= start_lba + image_blocks; } } /* <<< provisorily revoke the new size */ iso_lba = end_lba; if(iso_lba > end_lba) iso_lba= -1; } if(((off_t) iso_lba) * (off_t) 4 > hd_lba) { system_area_options= 0; } else if((xorriso->patch_system_area & 1) && ((off_t) iso_lba) * (off_t) 4 != hd_lba) { system_area_options= 0; } else if((xorriso->patch_system_area & 2) && ((off_t) iso_lba) * (off_t) 4 + (off_t) (63 * 256) < hd_lba) { system_area_options= 0; } else if(xorriso->patch_system_area & 2) { /* isohybrid patching */ /* Check whether bytes 432-345 point to ElTorito LBA */ hd_lba= ub[432] | (ub[433] << 8) | (ub[434] << 16) | (ub[435] << 24); ret= iso_image_get_boot_image(img, &bootimg, &bootimg_node, NULL); if(ret != 1) system_area_options= 0; else if(bootimg_node != NULL) { Xorriso__file_start_lba((IsoNode *) bootimg_node, &(iso_lba), 0); if(((off_t) iso_lba) * (off_t) 4 != hd_lba) system_area_options= 0; } } if(system_area_options == 0) { Xorriso_msgs_submit(xorriso, 0, "Loaded System Area data are not suitable for MBR patching.", 0, "DEBUG", 0); } } bufpt= buf; ret= 1; } else ret= 0; goto do_set; } if(strcmp(xorriso->system_area_disk_path, "/dev/zero") == 0) {ret= 1; goto do_set;} ret= Xorriso_afile_fopen(xorriso, xorriso->system_area_disk_path, "rb", &fp, 2); if(ret <= 0) {ret= 0; goto ex;} ret= fread(buf, 1, 32768, fp); if(ret < 32768) { if(ferror(fp)) { sprintf(xorriso->info_text, "Error when reading -boot_image system_area="); Text_shellsafe(xorriso->system_area_disk_path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); {ret= 0; goto ex;} } } bufpt= buf; do_set:; if(ret > 0 && xorriso->system_area_disk_path[0]) { sprintf(xorriso->info_text, "Copying to System Area: %d bytes from file ", ret); Text_shellsafe(xorriso->system_area_disk_path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); } ret= isoburn_igopt_set_system_area(sopts, bufpt, system_area_options); if(ret != ISO_SUCCESS) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", ret, "Error when attaching System Area data to ISO 9660 image", 0, "FAILURE", 1); {ret= 0; goto ex;} } ret= 1; ex:; if(fp != NULL && fp != stdin) fclose(fp); if(disc != NULL) isoburn_toc_disc_free(disc); 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, pacifier_speed= 0, data_lba, ext; int major, minor, micro; char xorriso_id[256], *img_id, sfe[5*SfileadrL], *cpt, *out_cs; 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; IsoNode *node, *root_node; ElToritoBootImage *bootimg; enum eltorito_boot_media_type emul_type= ELTORITO_NO_EMUL; int profile_number; char profile_name[80]; ret= Xorriso_finish_hl_update(xorriso, 0); if(ret <= 0) return(ret); out_cs= xorriso->out_charset; if(out_cs == NULL) Xorriso_get_local_charset(xorriso, &out_cs, 0); if(!(flag & 1)) { ret= Xorriso_auto_format(xorriso, 0); if(ret <=0 ) return(0); } 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 non-zero data"); 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); if(ret == 2) pacifier_speed= 1; else if(ret == 3) pacifier_speed= 2; ret= isoburn_igopt_new(&sopts, 0); if(ret<=0) { Xorriso_process_msg_queues(xorriso, 0); return(ret); } relax= xorriso->relax_compliance; xorriso->alignment= 0; image= isoburn_get_attached_image(source_drive); if(image != NULL) { iso_image_set_application_id(image, xorriso->application_id); iso_image_set_publisher_id(image, xorriso->publisher); iso_image_set_system_id(image, xorriso->system_id); iso_image_set_volset_id(image, xorriso->volset_id); } if((xorriso->do_aaip & 256) && out_cs != NULL) { static char *names = "isofs.cs"; size_t value_lengths[1]; value_lengths[0]= strlen(out_cs); ret= Xorriso_setfattr(xorriso, NULL, "/", (size_t) 1, &names, value_lengths, &out_cs, 2 | 8); if(ret<=0) goto ex; } ret= Xorriso_set_system_area(xorriso, source_drive, image, sopts, 0); if(ret <= 0) goto ex; /* Activate, adjust or discard boot image */ /* >>> ??? move down to libisoburn ? */ if(image!=NULL && !(flag&1)) { ret= iso_image_get_boot_image(image, &bootimg, NULL, NULL); /* >>> || xorriso->system_area_disk_path[0] */ if(xorriso->boot_image_bin_path[0]) { /* discard old boot image, set new one */ if(ret == 1) iso_image_remove_boot_image(image); if(xorriso->boot_image_emul == 1) emul_type= ELTORITO_HARD_DISC_EMUL; else if(xorriso->boot_image_emul == 2) emul_type= ELTORITO_FLOPPY_EMUL; if(xorriso->boot_image_cat_path[0] == 0) { strcpy(xorriso->boot_image_cat_path, xorriso->boot_image_bin_path); cpt= strrchr(xorriso->boot_image_cat_path, '/'); if(cpt == NULL) cpt= xorriso->boot_image_cat_path; else cpt++; strcpy(cpt, "boot.cat"); } sprintf(xorriso->info_text, "Activating boot image %s", Text_shellsafe(xorriso->boot_image_bin_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); sprintf(xorriso->info_text, "Creating El Torito boot catalog file %s", Text_shellsafe(xorriso->boot_image_cat_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= Xorriso_node_from_path(xorriso, image, xorriso->boot_image_bin_path, &node, 1); if(ret <= 0) { sprintf(xorriso->info_text, "Cannot find in ISO image: -boot_image ... bin_path=%s", Text_shellsafe(xorriso->boot_image_bin_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } ret= Xorriso_node_from_path(xorriso, image, xorriso->boot_image_cat_path, &node, 1); if(ret > 0) { if(!xorriso->do_overwrite) { sprintf(xorriso->info_text, "May not overwite existing -boot_image ... cat_path=%s", Text_shellsafe(xorriso->boot_image_cat_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } ret= Xorriso_rmi(xorriso, NULL, (off_t) 0, xorriso->boot_image_cat_path, 8 | (xorriso->do_overwrite == 1)); if(ret != 1) { sprintf(xorriso->info_text, "Could not remove existing -boot_image cat_path=%s", Text_shellsafe(xorriso->boot_image_cat_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } } ret= iso_image_set_boot_image(image, xorriso->boot_image_bin_path, emul_type, xorriso->boot_image_cat_path, &bootimg); if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", ret, "Error when attaching El-Torito boot image to ISO 9660 image", 0, "FAILURE", 1); sprintf(xorriso->info_text, "Could not attach El-Torito boot image to ISO 9660 image"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } el_torito_set_load_size(bootimg, xorriso->boot_image_load_size / 512); ret= Xorriso_set_isolinux_options(xorriso, image, 0); if(ret <= 0) goto ex; } else if(xorriso->patch_isolinux_image) { if(ret==1) { relax|= isoburn_igopt_allow_full_ascii; sprintf(xorriso->info_text, "Patching boot info table"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= Xorriso_path_from_lba(xorriso, NULL, xorriso->loaded_boot_bin_lba, sfe, 1); if(ret < 0) goto ex; if(ret == 0) { sprintf(xorriso->info_text, "Cannot patch boot image: no file found for its LBA."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); sprintf(xorriso->info_text, "Probably the loaded boot image file was deleted in this session."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); sprintf(xorriso->info_text, "Use -boot_image \"any\" \"discard\" or set new boot image"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0); goto ex; } ret= Xorriso_set_isolinux_options(xorriso, image, 0); if(ret <= 0) goto ex; } else { sprintf(xorriso->info_text, "Could not find any boot image for -boot_image patching"); 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); } } if((xorriso->do_aaip & 16) || !(xorriso->ino_behavior & 2)) { /* Overwrite isofs.st of root node by xorriso->isofs_st_out */ char *name= "isofs.st"; char timestamp[16], *value= timestamp; size_t value_length; sprintf(timestamp, "%.f", (double) xorriso->isofs_st_out); value_length= strlen(timestamp); Xorriso_setfattr(xorriso, NULL, "/", (size_t) 1, &name, &value_length, &value, 2 | 8); } isoburn_igopt_set_level(sopts, 3); ext= isoburn_igopt_rockridge | ((!!xorriso->do_joliet) * isoburn_igopt_joliet) | (( !(xorriso->ino_behavior & 2)) * isoburn_igopt_hardlinks) | (( (!(xorriso->ino_behavior & 2)) || (xorriso->do_aaip & (2 | 8 | 16 | 256)) || (xorriso->do_md5 & (2 | 4)) ) * isoburn_igopt_aaip) | ((!!(xorriso->do_md5 & 2)) * isoburn_igopt_session_md5) | ((!!(xorriso->do_md5 & 4)) * isoburn_igopt_file_md5) | ((!!(xorriso->do_md5 & 8)) * isoburn_igopt_file_stability); isoburn_igopt_set_extensions(sopts, ext); isoburn_igopt_set_relaxed(sopts, relax); 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, out_cs); isoburn_igopt_set_fifo_size(sopts, xorriso->fs * 2048); Ftimetxt(time(NULL), xorriso->scdbackup_tag_time, 8); isoburn_igopt_set_scdbackup_tag(sopts, xorriso->scdbackup_tag_name, xorriso->scdbackup_tag_time, xorriso->scdbackup_tag_written); 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); } isoburn_igopt_set_pvd_times(sopts, xorriso->vol_creation_time, xorriso->vol_modification_time, xorriso->vol_expiration_time, xorriso->vol_effective_time, xorriso->vol_uuid); /* Make final abort check before starting expensive activities */ ret= Xorriso_eval_problem_status(xorriso, 1, 0); if(ret<0) {ret= 0; goto ex;} if(xorriso->zisofs_by_magic) { sprintf(xorriso->info_text, "Checking disk file content for zisofs compression headers."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0); root_node= (IsoNode *) iso_image_get_root(image); ret= iso_node_zf_by_magic(root_node, (xorriso->out_drive_handle == xorriso->in_drive_handle) | 2 | 16); if(ret<0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when examining file content for zisofs headers", 0, "FAILURE", 1); } ret= Xorriso_eval_problem_status(xorriso, 1, 0); if(ret<0) {ret= 0; goto ex;} sprintf(xorriso->info_text, "Check for zisofs compression headers done."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0); } /* >>> omit iso_image_update_sizes if the image was filled up very quickly */; ret= iso_image_update_sizes(image); if(ret < 0) { Xorriso_process_msg_queues(xorriso, 0); if(ret<0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when updating file sizes", 0, "FAILURE", 1); } ret= Xorriso_eval_problem_status(xorriso, 1, 0); if(ret<0) {ret= 0; goto ex;} } Xorriso_set_abort_severity(xorriso, 1); if (xorriso->grow_blindly_msc2 >= 0 && xorriso->out_drive_handle != xorriso->in_drive_handle) { ret= isoburn_prepare_blind_grow(source_drive, &disc, sopts, drive, xorriso->grow_blindly_msc2); if(ret>0) { /* Allow the consumer of output to access the input drive */ source_drive= NULL; ret= Xorriso_give_up_drive(xorriso, 1|8); if(ret<=0) goto ex; } } else if(xorriso->out_drive_handle == xorriso->in_drive_handle || xorriso->in_drive_handle == NULL) { ret= isoburn_prepare_disc(source_drive, &disc, sopts); } else { ret= isoburn_prepare_new_image(source_drive, &disc, sopts, drive); } if(ret <= 0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text,"Failed to prepare session write run"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0); if(ret<=0) goto ex; isoburn_igopt_get_effective_lba(sopts, &(xorriso->session_lba)); if(xorriso->do_stream_recording == 2) { ret= isoburn_igopt_get_data_start(sopts, &data_lba); if(ret > 0 && data_lba >= 16) burn_write_opts_set_stream_recording(burn_options, data_lba); } 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; } ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) goto ex; /* Important: do not return until burn_is_aborting() was checked */ Xorriso_set_signal_handling(xorriso, 1); 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, pacifier_speed << 4); if(burn_is_aborting(0)) Xorriso_abort(xorriso, 0); /* Never comes back */ Xorriso_set_signal_handling(xorriso, 0); if(ret<=0) goto ex; if(!isoburn_drive_wrote_well(drive)) { isoburn_cancel_prepared_write(source_drive, drive, 0); 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\nWritten 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 to %s completed sucessfully.\n\n", Text_shellsafe(xorriso->outdev,sfe,0)); 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); if(image != NULL) iso_image_unref(image); isoburn_igopt_destroy(&sopts, 0); Xorriso_process_msg_queues(xorriso,0); Xorriso_append_scdbackup_record(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(burn_is_aborting(0)) return(2); 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= mkisofs 2= cdrecord bit4= report speed in CD units bit5= report speed in BD 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, date_text[80], *speed_unit, mem_text[8]; enum burn_drive_status drive_status; double start_time, current_time, last_time, base_time= 0.0, base_count= 0.0; double next_base_time= 0.0, next_base_count= 0.0, first_base_time= 0.0; double first_base_count= 0.0, norm= 0.0, now_time, fract_offset= 0.0; double measured_speed, speed_factor= 1385000, quot; time_t time_prediction; start_time= Sfile_microtime(0); while(burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING) usleep(100002); emul= flag&15; fract_offset= 0.2 * (double) emul - ((int) (0.2 * (double) emul)); if(emul==0) emul= xorriso->pacifier_style; speed_unit= "D"; if(flag&16) { speed_factor= 150.0*1024; speed_unit= "C"; } else if(flag & 32) { speed_factor= 4495625; speed_unit= "B"; } progress.sector= 0; current_time= Sfile_microtime(0); measured_speed= 0.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(current_time-last_time>0.2) measured_speed= (progress.sector - last_sector) * 2048.0 / (current_time - last_time); buffer_fill= 50; if(progress.buffer_capacity>0) buffer_fill= (double) (progress.buffer_capacity - progress.buffer_available) * 100.0 / (double) progress.buffer_capacity; if(emul==2) { 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); else ret= isoburn_get_fifo_status(drive, &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)); sprintf(xorriso->info_text+strlen(xorriso->info_text), " [buf %3d%%]", buffer_fill); if(current_time-last_time>0.2) sprintf(xorriso->info_text+strlen(xorriso->info_text), " %4.1fx.", measured_speed/speed_factor); } else if(emul == 1 && progress.sectors > 0 && progress.sector <= progress.sectors) { /* "37.87% done, estimate finish Tue Jul 15 18:55:07 2008" */ quot= ((double) progress.sector) / ((double) progress.sectors); sprintf(xorriso->info_text, " %2.2f%% done", quot*100.0); if(current_time - start_time >= 2 && quot > 0.0 && (quot >= 0.02 || progress.sector >= 5*1024)) { if(base_time == 0.0 && progress.sector >= 16*1024) { first_base_time= base_time= next_base_time= current_time; first_base_count= next_base_count= progress.sector; } else if(next_base_time > 0 && current_time - next_base_time >= 10) { base_time= next_base_time; base_count= next_base_count; next_base_time= current_time; next_base_count= progress.sector; } if(first_base_time > 0 && current_time - first_base_time >= 10 && progress.sectors > first_base_count && progress.sector > first_base_count) { norm= (1.0 - quot); if(norm < 0.0001) norm= 0.0001; quot= ((double) progress.sector - first_base_count) / ((double) progress.sectors - first_base_count); time_prediction= norm * (1.0 - quot) / quot * (current_time - first_base_time); } else { time_prediction= (1.0 - quot) / quot * (current_time - start_time); norm= 1.0; } if(base_time > 0 && current_time - base_time >= 10 && progress.sectors > base_count) { quot= ((double) progress.sector - base_count) / ((double) progress.sectors - base_count); time_prediction+= (1.0 - quot) / quot * (current_time - base_time); norm+= 1.0; } time_prediction/= norm; if(time_prediction < 30*86400 && time_prediction > 0) { time_prediction+= current_time + 1; Ftimetxt(time_prediction, date_text, 4); sprintf(xorriso->info_text+strlen(xorriso->info_text), ", estimate finish %s", date_text); } } } else { if(progress.sector<=progress.sectors) { if(progress.sectors <= 0) strcpy(mem_text, " 99.9"); else sprintf(mem_text, "%5.1f", 100.0 * ((double) progress.sector) / ((double) progress.sectors)); mem_text[5]= 0; sprintf(xorriso->info_text, "Writing: %10ds %s%% ", progress.sector, mem_text); } else { Sfile_scale(2048.0 * (double) progress.sector, mem_text, 5, 1e4, 1); sprintf(xorriso->info_text, "Writing: %10ds %s ", progress.sector, mem_text); } ret= isoburn_get_fifo_status(drive, &size, &free_bytes, &status_text); if(ret>0 ) sprintf(xorriso->info_text+strlen(xorriso->info_text), " fifo %3d%% buf %3d%%", (int) (100.0-100.0*((double) free_bytes)/(double) size), buffer_fill); if(current_time-last_time>0.2) sprintf(xorriso->info_text+strlen(xorriso->info_text), " %5.1fx%s ", measured_speed/speed_factor, speed_unit); } } 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. Working since %.f seconds.", current_time-start_time); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0); for(i= 0; i<12; i++) { /* 2 usleeps more than supposed to be needed */ Xorriso_process_msg_queues(xorriso, 0); if(aborting<=0) aborting= Xorriso_check_burn_abort(xorriso, 0); usleep(100000); now_time= Sfile_microtime(0); if(((time_t) now_time) - ((time_t) current_time) >= 1 && now_time - ((time_t) now_time) >= fract_offset) break; } } 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_process_msg_queues(xorriso,0); xorriso->pacifier_count++; if(xorriso->pacifier_count%10) return(1); Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0, "", 0); return(1); } /* @param flag bit0=silently return 0 if no volume/image is present */ int Xorriso_get_volume(struct XorrisO *xorriso, IsoImage **volume, int flag) { if(xorriso->in_volset_handle==NULL) { if(flag & 1) return(0); 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= "/"; if(volume == NULL) { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret <= 0) return(ret); } *node= NULL; ret= iso_tree_path_to_node(volume, path_pt, node); Xorriso_process_msg_queues(xorriso,0); if(ret<=0 || (*node)==NULL) { 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 bit3= return root directory as "/" and not as "" bit4= (with bit2) determine type of disk file eff_path and return 0 if not existing bit5= (with bit3) this is not a parameter bit6= insist in having an ISO image, even with bits1+2 @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; if((flag&64) || !(flag&2)) { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(ret); } eff_path[0]= 0; if(img_path[0]==0) { if(flag&8) strcpy(eff_path, "/"); return(2); /* root directory */ } 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) { if(flag&8) strcpy(eff_path, "/"); 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); } } if(flag&16) { ret= Sfile_type(eff_path, 1|(4*(xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&32))) )); if(ret<0) return(0); if(ret==2) is_dir= 1; } 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 */ int Xorriso_node_get_dev(struct XorrisO *xorriso, IsoNode *node, char *path, dev_t *dev, int flag) { *dev= iso_special_get_dev((IsoSpecial *) node); return(1); } /* @param flag bit0= *node is already valid bit1= add extra block for size estimation bit2= complain loudely if path is missing in image bit3= stbuf is to be used without eventual ACL bit4= try to obtain a better st_nlink count if hardlinks are enabled */ int Xorriso_fake_stbuf(struct XorrisO *xorriso, char *path, struct stat *stbuf, IsoNode **node, int flag) { int ret, min_hl, max_hl, node_idx, i; 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, !(flag&4)); if(ret<=0) *node= NULL; } if(*node==NULL) return(0); /* >>> stbuf->st_dev */ /* >>> stbuf->st_ino */ if(flag & 8) stbuf->st_mode= iso_node_get_perms_wo_acl(*node) & 07777; else 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_ISCHR(*node)) { stbuf->st_mode|= S_IFCHR; Xorriso_node_get_dev(xorriso, *node, path, &(stbuf->st_rdev), 0); } else if(LIBISO_ISBLK(*node)) { stbuf->st_mode|= S_IFBLK; Xorriso_node_get_dev(xorriso, *node, path, &(stbuf->st_rdev), 0); } else if(LIBISO_ISFIFO(*node)) stbuf->st_mode|= S_IFIFO; else if(LIBISO_ISSOCK(*node)) stbuf->st_mode|= S_IFSOCK; else if(LIBISO_ISBOOT(*node)) stbuf->st_mode|= Xorriso_IFBOOT; /* >>> With directories this should be : number of subdirs + 2 */ /* >>> ??? How to obtain RR hardlink number for other types ? */ /* This may get overriden farther down */ stbuf->st_nlink= 1; stbuf->st_uid= iso_node_get_uid(*node); stbuf->st_gid= iso_node_get_gid(*node); 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); if(LIBISO_ISDIR(*node) || (xorriso->ino_behavior & 1) || (!(flag & 16)) || xorriso->hln_array == NULL) return(1); /* Try to obtain a better link count */ ret= Xorriso_search_hardlinks(xorriso, *node, &node_idx, &min_hl, &max_hl, 0); if(ret < 0) return(ret); if(ret > 0 && node_idx >= 0) { for(i= min_hl; i <= max_hl; i++) { if(i == node_idx) continue; /* Check whether node is still valid */ if(iso_node_get_parent(xorriso->hln_array[i]) != NULL) stbuf->st_nlink++; } } return(1); } /* @param flag >>> bit0= follow links (i.e. stat() rather than lstat() bit1= do not return -2 on severe errors bit2= complain loudely if path is missing in image */ int Xorriso_iso_lstat(struct XorrisO *xorriso, char *path, struct stat *stbuf, int flag) { int ret; IsoNode *node; if(flag&1) { /* >>> follow link in ISO image */; } ret= Xorriso_fake_stbuf(xorriso, path, stbuf, &node, flag&4); if(ret>0) return(0); if(ret<0 && !(flag&2)) return(-2); return(-1); } /* @param flag bit0= give directory x-permission where is r-permission bit1= do not transfer ACL or xattr bit2= record dev,inode (only if enabled by xorriso) bit5= transfer ACL or xattr from eventual link target */ int Xorriso_transfer_properties(struct XorrisO *xorriso, struct stat *stbuf, char *disk_path, IsoNode *node, int flag) { mode_t mode; int ret= 1; size_t num_attrs= 0, *value_lengths= NULL; char **names= NULL, **values= NULL; mode= stbuf->st_mode; if((!(flag & 2)) && !(xorriso->do_aaip & 1)) /* Will drop ACL. Update mode S_IRWXG by eventual group:: ACL entry */ iso_local_get_perms_wo_acl(disk_path, &mode, flag & 32); 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); if((xorriso->do_aaip & 5) && !(flag & 2)) { ret= iso_local_get_attrs(disk_path, &num_attrs, &names, &value_lengths, &values, ((xorriso->do_aaip & 1) && !(flag & 2)) | ((!(xorriso->do_aaip & 4)) << 2) | (flag & 32)); if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, disk_path, ret, "Error when obtaining local ACL and xattr", 0, "FAILURE", 1 | 2); ret= 0; goto ex; } ret= iso_node_set_attrs(node, num_attrs, names, value_lengths, values, 1 | 8); if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", ret, "Error when setting ACL and xattr to image node", 0, "FAILURE", 1); ret= 0; goto ex; } } if((flag & 4) && ((xorriso->do_aaip & 16) || !(xorriso->ino_behavior & 2))) { ret= Xorriso_record_dev_inode(xorriso, disk_path, (dev_t) 0, (ino_t) 0, (void *) node, "", flag & 32); if(ret <= 0) goto ex; } ret= 1; ex:; Xorriso_process_msg_queues(xorriso,0); iso_local_get_attrs(disk_path, &num_attrs, &names, &value_lengths, &values, 1 << 15); /* free memory */ return(ret); } 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, stbuf_valid= 0; struct stat stbuf; char sfe[5*SfileadrL]; off_t size= 0; if(lstat(disk_path, &stbuf) != -1) { stbuf_valid= 1; if(S_ISREG(stbuf.st_mode)) size= stbuf.st_size; } if(flag&8) { if(cut_size > xorriso->file_size_limit && xorriso->file_size_limit > 0) { sprintf(xorriso->info_text, "File piece exceeds size limit of %.f bytes: %.f from %s\n", (double) xorriso->file_size_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(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; } else if(size > xorriso->file_size_limit && xorriso->file_size_limit > 0) { sprintf(xorriso->info_text, "File exceeds size limit of %.f bytes: %s\n", (double) xorriso->file_size_limit, Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } else { ret= iso_tree_add_new_node(volume, dir, img_name, disk_path, node); if(ret<0) goto ex; } } if(stbuf_valid && ((xorriso->do_aaip & 16) || !(xorriso->ino_behavior & 2))) { ret= Xorriso_record_dev_inode(xorriso, disk_path, stbuf.st_dev, stbuf.st_ino, (void *) *node, "", 1); 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); } if(LIBISO_ISREG(*node)) xorriso->pacifier_byte_count+= iso_file_get_size((IsoFile *) *node); return(1); } /* @param flag bit0= recursion is active bit1= do not report added files bit6= do not delete eventually existing node from di_array bit7= no special handling of split file directories */ 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; 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; 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= calloc(SfileadrL, 1); 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;} } 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); /* name is a pointer into disk_path */ 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;} } /* compare exclusions against disk_path resp. name */ ret= Xorriso_path_is_excluded(xorriso, disk_path, 0); /* (is never param) */ if(ret<0) {ret= -1; goto ex;} if(ret>0) continue; 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;} ret= Xorriso_resolve_link(xorriso, srcpt, link_target, 1); if(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 && !(flag & 128)) target_is_split= Xorriso_is_split(xorriso, "", (void *) node, 1 | 2); 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 | (flag & 64)); 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) { 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_set_change_pending(xorriso, 0); 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 | 64 | 128))); } 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: 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); 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_implicit_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 bit2= record dev,inode (only if enabled by xorriso) */ 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(flag & 1) { if(stat(disk_path, &stbuf)==-1) return(0); } else { if(lstat(disk_path, &stbuf)==-1) return(0); } Xorriso_transfer_properties(xorriso, &stbuf, disk_path, node, ((flag & 2) >> 1) | ((flag & 1) << 5) | (flag & 4)); Xorriso_set_change_pending(xorriso, 0); 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, -not_*: this is not a command parameter bit3= use offset and cut_size for cut_out_node bit4= return 3 on rejection by exclusion or user bit5= if directory then do not add sub tree bit6= do not delete eventually existing node from di_array bit7= no special handling of split file directories @return <=0 = error , 1 = added simple node , 2 = added directory , 3 = rejected */ 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; ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&4)); if(ret<0) return(ret); if(ret>0) return(3*!!(flag&16)); for(cpt= img_path; 1; cpt++) { 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 && !(flag & 128)) target_is_split= Xorriso_is_split(xorriso, "", (void *) node, 1 | 2); 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 | (flag & 64)); 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(3*!!(flag&16)); } 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_set_change_pending(xorriso, 0); 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_implicit_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, disk_path, (IsoNode *) dir, 4 | 32); if(!(flag&32)) { ret= Xorriso_add_tree(xorriso, dir, img_path, disk_path, NULL, flag & (2 | 64 | 128)); 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_set_change_pending(xorriso, 0); 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); ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&1)); if(ret!=0) return(0); 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); if(ret<=0) return(ret); ret= Xorriso_graft_in(xorriso, NULL, eff_source, eff_dest, startbyte, bytecount, 8); return(ret); } /* @param flag bit0= in_node is valid, do not resolve img_path bit1= test mode: print DEBUG messages @return <0 = error, 0 = surely not identical regular files , 1 = surely identical 2 = potentially depending on unknown disk file (e.g. -cut_out) */ int Xorriso_restore_is_identical(struct XorrisO *xorriso, void *in_node, char *img_path, char *disk_path, char type_text[5], int flag) { int ret; unsigned int fs_id; dev_t dev_id; ino_t ino_id; IsoStream *stream; IsoImage *volume; IsoNode *node; struct stat stbuf; int dummy; memset(type_text, 0, 5); if(!xorriso->volset_change_pending) return(0); if(flag&1) { node= (IsoNode *) in_node; } else { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(-1); ret= Xorriso_node_from_path(xorriso, volume, img_path, &node, 1); if(ret<=0) return(-1); } ret= Xorriso__file_start_lba(node, &dummy, 0); if(ret != 0) { Xorriso_process_msg_queues(xorriso, 0); return(0); } if(!LIBISO_ISREG(node)) return(0); stream= iso_file_get_stream((IsoFile *) node); memcpy(type_text, stream->class->type, 4); iso_stream_get_id(stream, &fs_id, &dev_id, &ino_id); if(flag&2) { sprintf(xorriso->info_text, "%s : fs=%d dev=%.f ino=%.f (%s)", img_path, fs_id, (double) dev_id, (double) ino_id, type_text); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); } ret= stat(disk_path, &stbuf); if(ret==-1) return(0); if(flag&2) { sprintf(xorriso->info_text, "%s : dev=%.f ino=%.f", disk_path, (double) stbuf.st_dev, (double) stbuf.st_ino); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); } if(fs_id!=1) return(2); /* >>> obtain underlying dev_t ino_t of type "cout" */; if(strcmp(type_text, "fsrc")!=0) return(2); if(stbuf.st_dev==dev_id && stbuf.st_ino==ino_id) return(1); return(0); } /* @param flag bit0= minimal transfer: access permissions only bit1= keep directory open: keep owner, allow rwx for owner and push directory onto xorriso->perm_stack */ int Xorriso_restore_properties(struct XorrisO *xorriso, char *disk_path, IsoNode *node, int flag) { int ret, is_dir= 0; mode_t mode; uid_t uid; gid_t gid; struct utimbuf utime_buffer; char sfe[5*SfileadrL]; struct stat stbuf; size_t num_attrs= 0, *value_lengths= NULL; char **names= NULL, **values= NULL; ret= lstat(disk_path, &stbuf); if(ret==-1) { sprintf(xorriso->info_text, "Cannot obtain properties of disk file %s", Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); {ret= 0; goto ex;} } uid= stbuf.st_uid; is_dir= S_ISDIR(stbuf.st_mode); mode= iso_node_get_permissions(node); if(xorriso->do_aaip & (2 | 8 | 16)) { ret= iso_node_get_attrs(node, &num_attrs, &names, &value_lengths, &values, (!!(xorriso->do_aaip & 2)) | (!(xorriso->do_aaip & (8 | 16))) << 2); if (ret < 0) { strcpy(xorriso->info_text, "Error with obtaining ACL and xattr for "); Text_shellsafe(disk_path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } if(num_attrs > 0) { ret= iso_local_set_attrs(disk_path, num_attrs, names, value_lengths, values, 0); if(ret < 0) { sprintf(xorriso->info_text, "Cannot change ACL or xattr of disk file %s", Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); {ret= 0; goto ex;} } } Xorriso_process_msg_queues(xorriso,0); } if(!(xorriso->do_aaip & 2)) mode= iso_node_get_perms_wo_acl(node); if(is_dir && (flag&2)) { ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1 | ((!!(xorriso->do_aaip & 2)) << 3)); if(ret<=0) {ret= 0; goto ex;} ret= Permstack_push(&(xorriso->perm_stack), disk_path, &stbuf, 0); if(ret<=0) { Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0); strcpy(xorriso->info_text, "Cannot memorize permissions for disk directory"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); {ret= -1; goto ex;} } mode|= S_IRUSR|S_IWUSR|S_IXUSR; } ret= chmod(disk_path, mode); if(ret==-1) { sprintf(xorriso->info_text, "Cannot change access permissions of disk file %s", Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); {ret= 0; goto ex;} } if(flag&1) {ret= 1; goto ex;} gid= iso_node_get_gid(node); if(!(S_ISDIR(stbuf.st_mode) && (flag&2))) uid= iso_node_get_uid(node); chown(disk_path, uid, gid); /* don't complain if it fails */ utime_buffer.actime= iso_node_get_atime(node); utime_buffer.modtime= iso_node_get_mtime(node); ret= utime(disk_path,&utime_buffer); if(ret==-1) { sprintf(xorriso->info_text, "Cannot change atime, mtime of disk file %s", Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); {ret= 0; goto ex;} } ret= 1; ex:; iso_node_get_attrs(node, &num_attrs, &names, &value_lengths, &values,1 << 15); return(ret); } /* @param flag bit1= minimal transfer: access permissions only bit2= keep directory open: keep owner, allow rwx for owner push to xorriso->perm_stack */ int Xorriso_restore_implicit_properties(struct XorrisO *xorriso, char *full_disk_path, char *disk_path, char *full_img_path, int flag) { int ret, nfic, ndc, nfdc, d, i; char nfi[SfileadrL], nd[SfileadrL], nfd[SfileadrL], *cpt; char sfe[5*SfileadrL]; struct stat stbuf; IsoNode *node; ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, full_disk_path, nfd, 1|2|4); if(ret<=0) return(ret); ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, disk_path, nd, 1|2); if(ret<=0) return(ret); ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, full_img_path, nfi, 1|2); if(ret<=0) return(ret); nfdc= Sfile_count_components(nfd, 0); ndc= Sfile_count_components(nd, 0); nfic= Sfile_count_components(nfi, 0); d= nfdc-ndc; if(d<0) return(-1); if(d>nfic) return(0); for(i= 0; i>1)&3)); if(ret<=0) return(ret); sprintf(xorriso->info_text, "Restored properties for %s", Text_shellsafe(nd, sfe, 0)); sprintf(xorriso->info_text+strlen(xorriso->info_text), " from %s", Text_shellsafe(nfi, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); return(1); } int Xorriso_is_plain_image_file(struct XorrisO *xorriso, void *in_node, char *path, int flag) { int ret, lba; IsoStream *stream; IsoNode *node; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) return(ret); } ret= Xorriso__file_start_lba(node, &lba, 0); if(ret > 0) { /* Stream source is from loaded image */ stream= iso_file_get_stream((IsoFile *) node); if(stream != NULL) if(iso_stream_get_input_stream(stream, 0) == NULL) return(1); } return(0); } /* @param flag bit0= Minimal transfer: access permissions only bit1= *_offset and bytes are valid for writing to regular file bit2= This is not a parameter. Do not report if ignored bit3= do not restore properties bit4= issue pacifier messages with long lasting copying bit7= return 4 if restore fails from denied permission do not issue error message @return <0 severe error , 0 failure , 1 success , 2 regularly not installed (disallowed device, UNIX domain socket) 4 with bit7: permission to restore was denied */ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, char *img_path, off_t img_offset, char *disk_path, off_t disk_offset, off_t bytes, int flag) { int ret= 0, write_fd= -1, wanted, wret, open_flags, l_errno= 0; int target_deleted= 0; char *what= "[unknown filetype]", sfe[5*SfileadrL], sfe2[5*SfileadrL]; char buf[32*1024], type_text[5], temp_path[SfileadrL], *buf_pt; char *link_target, *open_path_pt= NULL; off_t todo= 0, size, seek_ret, last_p_count= 0, already_done, read_count= 0; void *data_stream= NULL; mode_t mode; dev_t dev= 0; struct stat stbuf; struct utimbuf utime_buffer; if(LIBISO_ISDIR(node)) { what= "directory"; ret= mkdir(disk_path, 0777); l_errno= errno; } else if(LIBISO_ISREG(node)) { what= "regular file"; ret= Xorriso_iso_file_open(xorriso, img_path, (void *) node, &data_stream, 1); if(ret<=0) goto ex; open_path_pt= disk_path; ret= stat(open_path_pt, &stbuf); if(ret == -1 && errno == EACCES && (flag & 128)) {ret= 4; goto ex;} if(flag&2) { if(ret!=-1 && !S_ISREG(stbuf.st_mode)) { sprintf(xorriso->info_text, "Restore offset demanded. But filesystem path leads to non-data file %s", Text_shellsafe(disk_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); l_errno= 0; goto cannot_restore; } } else { /* If source and target are the same disk file then do not copy content */ ret= Xorriso_restore_is_identical(xorriso, (void *) node, img_path, disk_path, type_text, 1); if(ret<0) goto ex; if(ret==1) { /* preliminarily emulate touch (might get overridden later) */ utime_buffer.actime= stbuf.st_atime; utime_buffer.modtime= time(0); utime(disk_path,&utime_buffer); goto restore_properties; } if(ret==2) { /* Extract to temporary file and rename only after copying */ ret= Xorriso_make_tmp_path(xorriso, disk_path, temp_path, &write_fd, 128); if(ret <= 0 || ret == 4) goto ex; open_path_pt= temp_path; } } if(write_fd==-1) { open_flags= O_WRONLY|O_CREAT; if(disk_offset==0 || !(flag&2)) open_flags|= O_EXCL; write_fd= open(open_path_pt, open_flags, S_IRUSR|S_IWUSR); l_errno= errno; if(write_fd == -1 && errno == EACCES && (flag & 128)) {ret= 4; goto ex;} if(write_fd==-1) goto cannot_restore; } todo= size= iso_file_get_size((IsoFile *) node); if(flag&2) { if(bytesinfo_text, "Cannot address byte %.f in filesystem path %s", (double) disk_offset, Text_shellsafe(open_path_pt, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); goto cannot_restore; } } while(todo>0) { wanted= sizeof(buf); if(wanted>todo) wanted= todo; ret= Xorriso_iso_file_read(xorriso, data_stream, buf, wanted, 0); if(ret<=0) { if(xorriso->extract_error_mode == 0 && Xorriso_is_plain_image_file(xorriso, node, "", 0)) { close(write_fd); write_fd= -1; already_done= (size - todo) / (off_t) 2048; already_done*= (off_t) 2048; sprintf(xorriso->info_text, "Starting best_effort handling on ISO file %s at byte %.f", Text_shellsafe(img_path, sfe, 0), (double) already_done); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= Xorriso_read_file_data(xorriso, node, img_path, open_path_pt, already_done, already_done, size - already_done, 2); if(ret >= 0) xorriso->pacifier_byte_count+= todo; if(ret > 0) todo= 0; else todo= -1; } if(ret <= 0) { sprintf(xorriso->info_text, "Cannot read all bytes from ISO file %s", Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } break; } read_count+= ret; buf_pt= buf; if(img_offset > read_count - ret) { /* skip the desired amount of bytes */ if(read_count <= img_offset) continue; buf_pt= buf + (img_offset - (read_count - ret)); ret= read_count - img_offset; } wret= write(write_fd, buf_pt, ret); if(wret>=0) { todo-= wret; xorriso->pacifier_byte_count+= wret; if((flag&16) && xorriso->pacifier_byte_count - last_p_count >= 128*1024) { Xorriso_pacifier_callback(xorriso, "files restored", xorriso->pacifier_count, xorriso->pacifier_total, "", 2|4); last_p_count= xorriso->pacifier_byte_count; } } if(wret != ret) { sprintf(xorriso->info_text, "Cannot write all bytes to disk filesystem path %s", Text_shellsafe(open_path_pt, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); break; } } if(write_fd > 0) close(write_fd); write_fd= -1; if(todo > 0 && xorriso->extract_error_mode == 2 && open_path_pt != NULL) { unlink(open_path_pt); target_deleted= 1; } Xorriso_iso_file_close(xorriso, &data_stream, 0); data_stream= NULL; if(temp_path==open_path_pt && !target_deleted) { ret= rename(temp_path, disk_path); if(ret==-1) { sprintf(xorriso->info_text, "Cannot rename temporary path %s to final disk path %s", Text_shellsafe(temp_path, sfe, 0), Text_shellsafe(disk_path, sfe2, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); unlink(temp_path); ret= 0; goto ex; } } ret= -(todo > 0); l_errno= 0; } else if(LIBISO_ISLNK(node)) { what= "symbolic link"; link_target= (char *) iso_symlink_get_dest((IsoSymlink *) node); ret= symlink(link_target, disk_path); l_errno= errno; } else if(LIBISO_ISCHR(node)) { what= "character device"; if(xorriso->allow_restore!=2) { ignored:; if(!(flag&4)) { sprintf(xorriso->info_text, "Ignored file type: %s %s = %s", what, Text_shellsafe(img_path,sfe,0), Text_shellsafe(disk_path,sfe2,0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); } {ret= 2; goto ex;} } mode= S_IFCHR | 0777; ret= Xorriso_node_get_dev(xorriso, node, img_path, &dev, 0); if(ret<=0) goto ex; if(dev == (dev_t) 1) { probably_damaged:; sprintf(xorriso->info_text, "Most probably damaged device file not restored: mknod %s %s 0 1", Text_shellsafe(disk_path, sfe, 0), LIBISO_ISCHR(node) ? "c" : "b"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); ret= 0; goto ex; } ret= mknod(disk_path, mode, dev); l_errno= errno; } else if(LIBISO_ISBLK(node)) { what= "block device"; if(xorriso->allow_restore!=2) goto ignored; mode= S_IFBLK | 0777; ret= Xorriso_node_get_dev(xorriso, node, img_path, &dev, 0); if(ret<=0) goto ex; if(dev == (dev_t) 1) goto probably_damaged; ret= mknod(disk_path, mode, dev); l_errno= errno; } else if(LIBISO_ISFIFO(node)) { what= "named pipe"; mode= S_IFIFO | 0777; ret= mknod(disk_path, mode, dev); l_errno= errno; } else if(LIBISO_ISSOCK(node)) { what= "unix socket"; /* Restoring a socket file is not possible. One rather needs to restart the service which temporarily created the socket. */ goto ignored; } else { sprintf(xorriso->info_text, "Cannot restore file type '%s'", what); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0); ret= 0; goto ex; } if(ret == -1 && l_errno == EACCES && (flag & 128)) {ret= 4; goto ex;} if(ret==-1) { cannot_restore:; sprintf(xorriso->info_text, "Cannot restore %s to disk filesystem: %s", what, Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, l_errno, "FAILURE", 0); ret= 0; goto ex; } restore_properties:; if((flag&8) || LIBISO_ISLNK(node)) ret= 1; else ret= Xorriso_restore_properties(xorriso, disk_path, node, flag&1); if(todo < 0) ret= 0; ex:; if(write_fd >= 0) { close(write_fd); if(ret <= 0 && xorriso->extract_error_mode == 2 && open_path_pt != NULL) unlink(open_path_pt); } if(data_stream!=NULL) Xorriso_iso_file_close(xorriso, &data_stream, 0); return(ret); } /* Handle overwrite situation in disk filesystem. @param node intended source of overwriting or NULL @param flag bit4= return 3 on rejection by exclusion or user bit6= permission to call Xorriso_make_accessible() */ int Xorriso_restore_overwrite(struct XorrisO *xorriso, IsoNode *node, char *img_path, char *path, char *nominal_path, struct stat *stbuf, int flag) { int ret; char sfe[5*SfileadrL], sfe2[5*SfileadrL], type_text[5]; Xorriso_process_msg_queues(xorriso,0); if(xorriso->do_overwrite==1 || (xorriso->do_overwrite==2 && !S_ISDIR(stbuf->st_mode))) { ret= Xorriso_restore_is_identical(xorriso, (void *) node, img_path, path, type_text, (node!=NULL)); if(ret<0) return(ret); if(ret>0) /* will be handled properly by restore functions */ ret= Xorriso_reassure_restore(xorriso, path, 8); else ret= Xorriso_rmx(xorriso, (off_t) 0, path, 8 | (flag & 64)); if(ret<=0) return(ret); if(ret==3) { sprintf(xorriso->info_text, "User revoked restoring of (ISO) file: %s", Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(3*!!(flag&16)); } return(1); } Xorriso_msgs_submit(xorriso, 0, nominal_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "While restoring %s : %s exists and may not be overwritten", Text_shellsafe(nominal_path, sfe, 0), strcmp(nominal_path, path)==0 ? "file object" : Text_shellsafe(path, sfe2, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } /* @param flag bit0= do not accept hln_targets[i] != NULL as *node_idx bit1= use *node_idx as found index rather than searching it bit2= with bit1: use xorriso->node_array rather than hln_array */ int Xorriso_search_hardlinks(struct XorrisO *xorriso, IsoNode *node, int *node_idx, int *min_hl, int *max_hl, int flag) { int idx, ret, i, node_count; void *np, **node_array; node_array= xorriso->hln_array; node_count= xorriso->hln_count; *min_hl= *max_hl= -1; np= node; if(flag & 2) { idx= *node_idx; if(flag & 4) { node_array= xorriso->node_array; node_count= xorriso->node_counter; } } else { *node_idx= -1; ret= Xorriso_search_in_hln_array(xorriso, np, &idx, 0); if(ret <= 0) return(ret); } for(i= idx - 1; i >= 0 ; i--) if(Xorriso__findi_sorted_ino_cmp(&(node_array[i]), &np) != 0) break; *min_hl= i + 1; for(i= idx + 1; i < node_count; i++) if(Xorriso__findi_sorted_ino_cmp(&(node_array[i]), &np) != 0) break; *max_hl= i - 1; /* Search for *node_idx */ if(flag & 2) return(1); for(i= *min_hl; i <= *max_hl; i++) if(node_array[i] == np) { if((flag & 1) && xorriso->hln_targets != NULL && !(flag & 4)) if(xorriso->hln_targets[i] != NULL) continue; *node_idx= i; break; } return(1); } /* @return <0 error, bit0= hardlink created bit1= siblings with target NULL found bit2= siblings with non-NULL target found */ int Xorriso_restore_target_hl(struct XorrisO *xorriso, IsoNode *node, char *disk_path, int *node_idx, int flag) { int ret, min_hl, max_hl, i, null_target_sibling= 0, link_sibling= 0; if(xorriso->hln_targets == NULL) return(0); ret= Xorriso_search_hardlinks(xorriso, node, node_idx, &min_hl, &max_hl, 1); if(ret < 0) return(ret); if(ret == 0 || *node_idx < 0 || min_hl == max_hl) return(0); for(i= min_hl; i <= max_hl; i++) { if(xorriso->hln_targets[i] == NULL) { if(i != *node_idx) null_target_sibling= 1; continue; } link_sibling= 1; ret= Xorriso_restore_make_hl(xorriso, xorriso->hln_targets[i], disk_path, !!xorriso->do_auto_chmod); if(ret > 0) return(1); } return((null_target_sibling << 1) | (link_sibling << 2)); } /* @return <0 error, bit0= hardlink created bit2= siblings lower index found */ int Xorriso_restore_prefix_hl(struct XorrisO *xorriso, IsoNode *node, char *disk_path, int node_idx, int flag) { int ret, min_hl, max_hl, i, link_sibling= 0, hflag; char old_path[SfileadrL], img_path[SfileadrL]; struct Xorriso_lsT *img_prefixes= NULL, *disk_prefixes= NULL; ret= Xorriso_search_hardlinks(xorriso, node, &node_idx, &min_hl, &max_hl, 2 | 4); if(ret < 0) return(ret); if(ret == 0 || min_hl == max_hl) return(0); for(i= min_hl; i < node_idx; i++) { link_sibling= 1; ret= Xorriso_path_from_node(xorriso, xorriso->node_array[i], img_path, 0); if(ret < 0) return(ret); if(ret == 0) continue; /* Node is deleted from tree (Should not happen here) */ hflag= 1; if(i == min_hl) { hflag= 0; } else if(xorriso->node_array[i] != xorriso->node_array[i - 1]) { hflag= 0; } if(hflag == 0) { img_prefixes= xorriso->node_img_prefixes; disk_prefixes= xorriso->node_disk_prefixes; } ret= Xorriso_make_restore_path(xorriso, &img_prefixes, &disk_prefixes, img_path, old_path, hflag); if(ret <= 0) return(ret); ret= Xorriso_restore_make_hl(xorriso, old_path, disk_path, !!xorriso->do_auto_chmod); if(ret > 0) return(1); } return(link_sibling << 2); } /* @return <0 = error , 0 = availmem exhausted first time , 1 = ok 2 = availmem exhausted repeated */ int Xorriso_register_node_target(struct XorrisO *xorriso, int node_idx, char *disk_path, int flag) { int l; if(xorriso->node_targets_availmem == 0) return(2); if(xorriso->hln_targets == NULL || node_idx < 0 || node_idx >= xorriso->hln_count) return(0); if(xorriso->hln_targets[node_idx] != NULL) { xorriso->node_targets_availmem+= strlen(xorriso->hln_targets[node_idx]) +1; free(xorriso->hln_targets[node_idx]); } l= strlen(disk_path); if(xorriso->node_targets_availmem <= l + 1) { sprintf(xorriso->info_text, "Hardlink target buffer exceeds -temp_mem_limit. Hardlinks may get divided."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); xorriso->node_targets_availmem= 0; return(0); } xorriso->hln_targets[node_idx]= strdup(disk_path); if(xorriso->hln_targets[node_idx] == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } xorriso->node_targets_availmem-= (l + 1); return(1); } /* @param flag bit0= offset and bytes is valid for writing to regular file bit1= do not report copied files bit2= -follow, -not_*: this is not a command parameter bit3= keep directory open: keep owner, allow rwx for owner bit4= do not look for hardlinks even if enabled bit6= this is a copy action: do not fake times and ownership bit7= return 4 if restore fails from denied permission do not issue error message @return <=0 = error , 1 = added leaf file object , 2 = added directory , 3= regularly not installed (disallowed device, UNIX domain socket) 4 = with bit7: permission to restore was denied */ int Xorriso_restore_disk_object(struct XorrisO *xorriso, char *img_path, IsoNode *node, char *disk_path, off_t offset, off_t bytes, int flag) { int ret, i, split_count= 0, partno, total_parts, leaf_is_split= 0; int record_hl_path= 0, node_idx, cannot_register= 0; off_t total_bytes, was_byte_count; char *part_name, part_path[SfileadrL], *img_path_pt; char sfe[5*SfileadrL], sfe2[5*SfileadrL]; IsoImage *volume; IsoNode *part_node, *first_part_node= NULL; struct SplitparT *split_parts= NULL; struct stat stbuf; ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; was_byte_count= xorriso->pacifier_byte_count; if(LIBISO_ISDIR(node) && xorriso->do_concat_split) leaf_is_split= Xorriso_identify_split(xorriso, img_path, node, &split_parts, &split_count, &stbuf, 1|2); if(leaf_is_split) { /* map all files in directory img_path into regular file disk_path */ for(i=0 ; itotal_bytes) bytes= total_bytes-offset; ret= Xorriso_tree_restore_node(xorriso, part_node, part_path, (off_t) 0, disk_path, offset, bytes, (!!(flag&64)) | 2 | (flag & (4 | 128)) | 8 | ( 16 * !(flag&2))); if(ret<=0) goto restoring_failed; if(ret == 4) goto ex; } if(first_part_node!=NULL) Xorriso_restore_properties(xorriso, disk_path, first_part_node, !!(flag&64)); goto went_well; } #ifdef Osirrox_not_yeT if(resolve_link) { ret= Xorriso_resolve_link(xorriso, disk_path, resolved_disk_path, 0); if(ret<=0) goto ex; disk_path_pt= resolved_disk_path; } else #endif /* Osirrox_not_yeT */ img_path_pt= img_path; if(!((xorriso->ino_behavior & 4) || (flag & (1 | 16)) || LIBISO_ISDIR(node))){ /* Try to restore as hardlink */ ret= Xorriso_restore_target_hl(xorriso, node, disk_path, &node_idx, !!xorriso->do_auto_chmod); if(ret < 0) { goto ex; } else if(ret & 1) { /* Success, hardlink was created */ goto went_well; } else if(ret & 2) { /* Did not establish hardlink. Hardlink siblings with target NULL found.*/ record_hl_path= 1; } if(ret & 4) { /* Found siblings with non-NULL target, but did not link. */ ret= Xorriso_eval_problem_status(xorriso, 1, 0); if(ret < 0) {ret= 0; goto ex;} } } ret= Xorriso_tree_restore_node(xorriso, node, img_path_pt, (off_t) 0, disk_path, offset, bytes, (flag&(4 | 8 | 128)) | (!!(flag&64)) | ((flag&1)<<1) | ( 16 * !(flag&2))); if(ret == 4) goto ex; if(ret>0 && (flag&8)) ret= Xorriso_restore_properties(xorriso, disk_path, node, 2 | !!(flag&64)); if(ret<=0) { restoring_failed:; sprintf(xorriso->info_text, "Restoring 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); {ret= 0; goto ex;} } if(ret==2) {ret= 3; goto ex;} if(record_hl_path) { /* Start of a disk hardlink family */ ret= Xorriso_register_node_target(xorriso, node_idx, disk_path, 0); if(ret < 0) goto ex; if(ret == 0) cannot_register= 1; } went_well:; xorriso->pacifier_count++; if(!(flag&2)) Xorriso_pacifier_callback(xorriso, "files restored", xorriso->pacifier_count, xorriso->pacifier_total, "", 4); ret= 1; ex:; if(split_parts!=NULL) Splitparts_destroy(&split_parts, split_count, 0); if(ret > 0 && cannot_register) ret= 0; return(ret); } /* @param flag bit0= source is a directory and not to be restored as split file >>> bit6= permission to call Xorriso_make_accessible() @return <=0 error , 1=collision handled , 2=no collision , 3=revoked by user */ int Xorriso_handle_collision(struct XorrisO *xorriso, IsoNode *node, char *img_path, char *disk_path, char *nominal_disk_path, int *stbuf_ret, int flag) { int ret, target_is_dir= 0, target_is_link= 0, stat_ret, made_accessible= 0; struct stat target_stbuf, lt_stbuf; struct PermiteM *perm_stack_mem; perm_stack_mem= xorriso->perm_stack; /* does a disk file exist with this name ? */ *stbuf_ret= lstat(disk_path, &target_stbuf); if(*stbuf_ret==-1) { if((flag & 64) && errno == EACCES) { ret= Xorriso_make_accessible(xorriso, disk_path, 0); if(ret < 0) goto ex; made_accessible= 1; *stbuf_ret= lstat(disk_path, &target_stbuf); } if(*stbuf_ret==-1) {ret= 2; goto ex;} } target_is_link= S_ISLNK(target_stbuf.st_mode); if(target_is_link) { stat_ret= stat(disk_path, <_stbuf); if(stat_ret == -1) { if((flag & 64) && errno == EACCES && !made_accessible) { ret= Xorriso_make_accessible(xorriso, disk_path, 0); if(ret < 0) goto ex; made_accessible= 1; stat_ret= stat(disk_path, <_stbuf); } } if(stat_ret != -1) target_is_dir= S_ISDIR(lt_stbuf.st_mode); } else { target_is_dir= S_ISDIR(target_stbuf.st_mode); } if(target_is_dir && (!target_is_link) && !(flag&1)) { strcpy(xorriso->info_text, "Attempt to replace DISK directory "); Text_shellsafe(nominal_disk_path, xorriso->info_text+strlen(xorriso->info_text), 0); strcat(xorriso->info_text, " by ISO file "); Text_shellsafe(img_path, xorriso->info_text+strlen(xorriso->info_text), 0); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } if(!(target_is_dir && (flag&1))) { Xorriso_process_msg_queues(xorriso,0); ret= Xorriso_restore_overwrite(xorriso, node, img_path, disk_path, nominal_disk_path, &target_stbuf, 16 | (flag & 64)); if(ret==3) {ret= 3; goto ex;} if(ret<=0) goto ex; *stbuf_ret= -1; /* It might still exist but will be handled properly */ } ret= 1; ex:; if(made_accessible) Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, 0); return(ret); } /* @param flag bit0= recursion is active bit1= do not report restored files bit6= this is a copy action: do not fake times and ownership bit8= only register non-directory nodes in xorriso->node_array bit7+8= 0= direct operation 1= create only directories, count nodes in xorriso->node_counter 2= only register non-directory nodes in xorriso->node_array 3= count nodes in xorriso->node_counter, create no directory */ int Xorriso_restore_tree(struct XorrisO *xorriso, IsoDir *dir, char *img_dir_path, char *disk_dir_path, off_t boss_mem, struct LinkiteM *link_stack, int flag) { IsoImage *volume; IsoNode *node; IsoDirIter *iter= NULL; IsoNode **node_array= NULL; int node_count, node_idx; int ret, source_is_dir, source_is_link, fret, was_failure= 0; int do_not_dive, source_is_split= 0, len_dp, len_ip, stbuf_ret, hflag, hret; char *name, *disk_name, *leaf_name, *srcpt, *stbuf_src= ""; struct LinkiteM *own_link_stack; char *sfe= NULL, *sfe2= NULL; char *disk_path= NULL, *img_path= NULL, *link_target= NULL; off_t mem; struct PermiteM *perm_stack_mem; struct stat stbuf; int dir_create= 0, node_register= 0, do_node_count= 0, normal_mode= 0; perm_stack_mem= xorriso->perm_stack; switch((flag >> 7) & 3) { case 0: normal_mode= 1; break; case 1: dir_create= 1; break; case 2: node_register= 1; break; case 3: do_node_count= 1; } /* 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;} } own_link_stack= link_stack; ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; stbuf_src= img_dir_path; node= (IsoNode *) dir; ret= Xorriso_fake_stbuf(xorriso, stbuf_src, &stbuf, &node, 1); if(ret<=0) { Xorriso_msgs_submit(xorriso, 0, disk_dir_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text,"Cannot open as (ISO) source directory: %s", Text_shellsafe(img_dir_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } #ifdef Osirrox_not_yeT dev_t dir_dev; 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;} } #endif /* Osirrox_not_yeT */ if(!S_ISDIR(stbuf.st_mode)) { Xorriso_msgs_submit(xorriso, 0, disk_dir_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text,"Is not a directory in ISO image: %s", Text_shellsafe(img_dir_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } mem= boss_mem; ret= Xorriso_findi_iter(xorriso, dir, &mem, &iter, &node_array, &node_count, &node_idx, &node, 1 | 4 * (normal_mode && (xorriso->ino_behavior & 4))); if(ret<=0) goto ex; if(Sfile_str(img_path, img_dir_path,0)<=0) { much_too_long:; Xorriso_much_too_long(xorriso, SfileadrL, 2); {ret= 0; goto ex;} } if(img_path[0]==0 || img_path[strlen(img_path)-1]!='/') strcat(img_path,"/"); name= img_path+strlen(img_path); if(Sfile_str(disk_path, disk_dir_path, 0)<=0) goto much_too_long; if(disk_path[0]==0 || disk_path[strlen(disk_path)-1]!='/') strcat(disk_path,"/"); disk_name= disk_path+strlen(disk_path); len_dp= strlen(disk_path); len_ip= strlen(img_path); while(1) { /* loop over ISO directory content */ stbuf_src= ""; #ifdef Osirrox_not_yeT Linkitem_reset_stack(&own_link_stack, link_stack, 0); #endif srcpt= img_path; Xorriso_process_msg_queues(xorriso,0); ret= Xorriso_findi_iter(xorriso, dir, &mem, &iter, &node_array, &node_count, &node_idx, &node, 0); if(ret<0) goto ex; if(ret==0 || xorriso->request_to_abort) break; leaf_name= (char *) iso_node_get_name(node); if(Xorriso_much_too_long(xorriso, len_dp + strlen(leaf_name)+1, 0)<=0) {ret= 0; goto was_problem;} if(Xorriso_much_too_long(xorriso, len_ip + strlen(leaf_name)+1, 0)<=0) {ret= 0; goto was_problem;} /* name is a pointer into img_path */ strcpy(name, leaf_name); strcpy(disk_name, leaf_name); stbuf_src= srcpt; ret= Xorriso_fake_stbuf(xorriso, img_path, &stbuf, &node, 1); if(ret<=0) goto was_problem; source_is_dir= 0; source_is_link= S_ISLNK(stbuf.st_mode); #ifdef Osirrox_not_yeT /* ??? Link following in the image would cause severe problems with Xorriso_path_from_node() */ 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; } #endif /* Osirrox_not_yeT */ do_not_dive= 0; if(S_ISDIR(stbuf.st_mode)) source_is_dir= 1; source_is_split= 0; if(source_is_dir) source_is_split= Xorriso_is_split(xorriso, img_path, node, 1|2); if(source_is_split) do_not_dive= 1; if(source_is_dir || !(dir_create || do_node_count || node_register)) { ret= Xorriso_handle_collision(xorriso, node, img_path, disk_path, disk_path, &stbuf_ret, (source_is_dir && !source_is_split)); if(ret<=0 || ret==3) goto was_problem; } else { stbuf_ret= -1; } if(stbuf_ret!=-1) { /* (Can only happen with directory) */ Xorriso_auto_chmod(xorriso, disk_path, 0); } else { hflag= 4 | (flag & (2|64)); if(source_is_dir && !do_not_dive) hflag|= 8; /* keep directory open for user */ if((dir_create || do_node_count) && !source_is_dir) { xorriso->node_counter++; } else if(node_register && !source_is_dir) { if(xorriso->node_counter < xorriso->node_array_size) { xorriso->node_array[xorriso->node_counter++]= (void *) node; iso_node_ref(node); } } else if(node_register || do_node_count) { ret= 1; } else { ret= Xorriso_restore_disk_object(xorriso, img_path, node, disk_path, (off_t) 0, (off_t) 0, hflag); } if(ret<=0) goto was_problem; } if(source_is_dir && !do_not_dive) { ret= Xorriso_restore_tree(xorriso, (IsoDir *) node, img_path, disk_path, mem, own_link_stack, 1 | (flag & (2 | (3 << 7)))); /* eventually restore exact access permissions of directory */ hret= Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, !!(flag&64)); if(hret<=0 && hretperm_stack), perm_stack_mem, xorriso, !!(flag&64)); } ret= 1; ex: Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, !!(flag&64)); 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); Xorriso_findi_iter(xorriso, dir, &mem, &iter, &node_array, &node_count, &node_idx, &node, (1<<31)); Xorriso_process_msg_queues(xorriso,0); #ifdef Osirrox_not_yeT Linkitem_reset_stack(&own_link_stack, link_stack, 0); #endif if(ret<=0) return(ret); return(!was_failure); } /* @param flag >>> bit0= mkdir: graft in as empty directory, not as copy from iso bit1= do not report copied files bit2= -follow, -not_*: this is not a command parameter bit3= use offset and cut_size for -paste_in bit4= return 3 on rejection by exclusion or user bit5= if directory then do not add sub tree bit6= this is a copy action: do not fake times and ownership bit7+8= operation mode 0= direct operation 1= create only directories, count nodes in xorriso->node_counter 2= only register non-directory nodes in xorriso->node_array 3= count nodes in xorriso->node_counter, create no directory bit9= with operation mode 1 do net register prefixes @return <=0 = error , 1 = added leaf file object , 2 = added directory , 3 = rejected */ int Xorriso_restore(struct XorrisO *xorriso, char *img_path, char *disk_path, off_t offset, off_t bytes, int flag) { IsoImage *volume; char path[SfileadrL], *apt, *npt, sfe[5*SfileadrL]; IsoNode *node= NULL; int done= 0, is_dir= 0, ret, source_is_dir, stbuf_ret, hret; int dir_create= 0, node_count= 0, node_register= 0; int leaf_is_split= 0, source_is_split= 0, new_dir_made= 0; struct stat stbuf; struct PermiteM *perm_stack_mem; perm_stack_mem= xorriso->perm_stack; switch((flag >> 7) & 3) { case 1: dir_create= 1; break; case 2: node_register= 1; break; case 3: node_count= 1; } if(dir_create && !(flag & (1 << 9))) { ret= Xorriso_lst_append_binary(&(xorriso->node_disk_prefixes), disk_path, strlen(disk_path) + 1, 0); if(ret <= 0) goto ex; ret= Xorriso_lst_append_binary(&(xorriso->node_img_prefixes), img_path, strlen(img_path) + 1, 0); if(ret <= 0) goto ex; } ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&4)); if(ret<0) goto ex; if(ret>0) {ret= 3*!!(flag&16); goto ex;} ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; strncpy(path, disk_path, sizeof(path)-1); path[sizeof(path)-1]= 0; apt= npt= path; if(!(flag&1)) { ret= Xorriso_fake_stbuf(xorriso, img_path, &stbuf, &node, 0); if(ret>0) { if(S_ISDIR(stbuf.st_mode)) is_dir= 1; #ifdef Osirrox_not_yeT /* ??? this would cause severe problems with Xorriso_path_from_node() */ else if((stbuf.st_mode&S_IFMT)==S_IFLNK && (xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&4)))) { resolve_link= 1; ret= Xorriso_iso_lstat(xorriso, img_path, &stbuf, 1|2); if(ret!=-1) { if(S_ISDIR(stbuf.st_mode)) is_dir= 1; } } #endif /* Osirrox_not_yeT */ } else { Xorriso_process_msg_queues(xorriso,0); Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "Cannot determine attributes of (ISO) source file %s", Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); ret= 0; goto ex; } if(is_dir && xorriso->do_concat_split) leaf_is_split= Xorriso_is_split(xorriso, img_path, node, 1|2); } 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); source_is_split= done && leaf_is_split; stbuf_ret= -1; if((flag&8) && done) { /* ??? move down from Xorriso_paste_in() : check whether target does not exist or both are regular */; } else if(source_is_dir || !(dir_create || node_count || node_register)) { ret= Xorriso_handle_collision(xorriso, node, img_path, path, disk_path, &stbuf_ret, (source_is_dir && !source_is_split)); if(ret<=0 || ret==3) goto ex; } new_dir_made= 0; if(stbuf_ret==-1 && (source_is_dir && !source_is_split) && !(node_count || node_register)) { /* make a directory */ ret= mkdir(path, 0777); if(ret==-1) { Xorriso_process_msg_queues(xorriso,0); Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "While restoring '%s' : could not insert '%s'", disk_path, path); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); {ret= 0; goto ex;} } if(!done) { /* keep rwx for the owner */ Xorriso_restore_implicit_properties(xorriso, disk_path, path, img_path, 4); } new_dir_made= 1; } else if((source_is_dir && !source_is_split)) { if(!(node_count || node_register)) Xorriso_auto_chmod(xorriso, path, 0); } if(done) { attach_source:; if(flag&1) { /* directory was created above */; } else if(is_dir && !source_is_split) { if(!node_register) { if(new_dir_made) /* keep open and push to Permstack */ Xorriso_restore_properties(xorriso, disk_path, node, 2 | !!(flag&64)); } if(!(flag&32)) { ret= Xorriso_restore_tree(xorriso, (IsoDir *) node, img_path, path, (off_t) 0, NULL, flag & (2 | 64 | (3 << 7))); if(ret<=0) goto ex; if(new_dir_made && !(flag&64)) /* set timestamps which Permstack_pop() will not set */ Xorriso_restore_properties(xorriso, disk_path, node, 2); } } else { if(dir_create || node_count) { xorriso->node_counter++; } else if(node_register) { if(xorriso->node_counter < xorriso->node_array_size) { xorriso->node_array[xorriso->node_counter++]= (void *) node; iso_node_ref(node); } } else { ret= Xorriso_restore_disk_object(xorriso, img_path, node, path, offset, bytes, (flag & (2|4|64)) | !!(flag&8)); if(ret<=0) goto ex; } } } else *npt= '/'; } Xorriso_process_msg_queues(xorriso,0); ret= 1 + (is_dir && !leaf_is_split); ex:; /* restore exact access permissions of stacked paths */ hret= Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, 2 | !!(flag&64)); if(hret<=0 && hretperm_stack; Xorriso_sort_node_array(xorriso, 0); disk_path[0]= 0; for(i= 0; i < xorriso->node_counter; i++) { node= (IsoNode *) xorriso->node_array[i]; ret= Xorriso_path_from_node(xorriso, node, img_path, 0); if(ret < 0) goto ex; if(ret == 0) continue; /* Node is deleted from tree (Should not happen here) */ hflag= 1; if(i == 0) { hflag= 0; } else if(node != xorriso->node_array[i - 1]) { hflag= 0; } if(hflag == 0) { img_prefixes= xorriso->node_img_prefixes; disk_prefixes= xorriso->node_disk_prefixes; } ret= Xorriso_make_restore_path(xorriso, &img_prefixes, &disk_prefixes, img_path, disk_path, hflag); if(ret<=0) goto was_problem; ret= Xorriso_handle_collision(xorriso, node, img_path, disk_path, disk_path, &stbuf_ret, 64); if(ret<=0 || ret==3) goto was_problem; if(xorriso->hln_array != NULL && !(xorriso->ino_behavior & 16)) { /* Eventual lookup of hardlinks will be done in Xorriso_restore_disk_object() */; } else if(i > 0 && !(xorriso->ino_behavior & 4)) { if(Xorriso__findi_sorted_ino_cmp(&(xorriso->node_array[i-1]), &(xorriso->node_array[i])) == 0) { if(faulty_family) { sprintf(xorriso->info_text, "Hardlinking omitted with "); Text_shellsafe(disk_path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); } else { /* Try to install hardlink to a sibling */ ret= Xorriso_restore_prefix_hl(xorriso, node, disk_path, i, 0); if(ret < 0) { goto was_problem; } else if(ret & 1) { /* Success, hardlink was created */ xorriso->pacifier_count++; continue; } if(ret & 4) { /* Found elder siblings, but did not link. */ ret= Xorriso_eval_problem_status(xorriso, 1, 0); if(ret < 0) {ret= 0; goto ex;} } } } else faulty_family= 0; } ret= Xorriso_restore_disk_object(xorriso, img_path, node, disk_path, (off_t) 0, (off_t) 0, 4 | (xorriso->ino_behavior & 16) | 128); if(ret<=0) goto was_problem; if(ret == 4) { /* Failed from lack of permission */ ret= Xorriso_make_accessible(xorriso, disk_path, 0); if(ret < 0) goto ex; ret= Xorriso_restore_disk_object(xorriso, img_path, node, disk_path, (off_t) 0, (off_t) 0, 4 | (xorriso->ino_behavior & 16)); if(ret<=0) goto was_problem; Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, 0); } continue; /* regular bottom of loop */ was_problem:; faulty_family= 1; was_failure= 1; fret= Xorriso_eval_problem_status(xorriso, ret, 1|2); if(fret<0) goto ex; Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, 0); } ret= 1; ex:; Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso, 0); return(ret); } /* @param flag bit0= -follow, -not: disk_path is not a command parameter */ int Xorriso_paste_in(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; IsoNode *node; ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, disk_path, eff_dest, 2|4); if(ret<=0) return(ret); ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&1)); if(ret!=0) return(0); ret= stat(eff_dest, &stbuf); if(ret!=-1 && !S_ISREG(stbuf.st_mode)) { Xorriso_msgs_submit(xorriso, 0, eff_dest, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-paste_in: DISK file %s exists and is not a data file", 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_source, 2); if(ret<=0) return(ret); ret= Xorriso_fake_stbuf(xorriso, eff_source, &stbuf, &node, 4); if(ret<=0) return(0); if(!S_ISREG(stbuf.st_mode)) { Xorriso_msgs_submit(xorriso, 0, eff_dest, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-paste_in: ISO file %s is not a data file", Text_shellsafe(eff_source, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); return(0); } /* >>> eventually obtain parameters from file name */; ret= Xorriso_restore(xorriso, 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 bit3=report to info channel (else to result channel) */ int Xorriso_toc_line(struct XorrisO *xorriso, int flag) { if(!(flag & 8)) { Xorriso_result(xorriso,0); return(1); } strcpy(xorriso->info_text, xorriso->result_line); Xorriso_info(xorriso, 0); return(1); } /* @param flag bit0= no output if no boot record was found bit1= short form bit3= report to info channel (else to result channel) */ int Xorriso_show_boot_info(struct XorrisO *xorriso, int flag) { int ret, bin_path_valid= 0,has_isolinux_mbr= 0, i; unsigned int mbr_lba= 0; off_t lb0_count; char *respt, sfe[5*SfileadrL], path[SfileadrL]; unsigned char lb0[2048]; struct burn_drive_info *dinfo; struct burn_drive *drive; IsoImage *image= NULL; ElToritoBootImage *bootimg; IsoFile *bootimg_node; IsoBoot *bootcat_node; respt= xorriso->result_line; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to print boot info", 16); if(ret<=0) goto no_boot; image= isoburn_get_attached_image(drive); if(image == NULL) { ret= 0; no_boot:; if(!(flag & 1)) { sprintf(respt, "Boot record : none\n"); Xorriso_toc_line(xorriso, flag & 8); } return(ret); } /* Important: no return before iso_image_unref(image); */ /* Using the nodes with extreme care . They might be deleted meanwhile. */ ret= iso_image_get_boot_image(image, &bootimg, &bootimg_node, &bootcat_node); iso_image_unref(image); /* release obtained reference */ image= NULL; if(ret != 1) goto no_boot; ret= Xorriso_path_from_lba(xorriso, NULL, xorriso->loaded_boot_bin_lba, path, 1); if(ret > 0) bin_path_valid= 1; sprintf(respt, "Boot record : El Torito"); if(bin_path_valid) ret= Xorriso_is_isohybrid(xorriso, bootimg_node, 0); else ret= 0; if(ret > 0) { /* Load and examine potential MBR */ ret= burn_read_data(drive, (off_t) 0, (char *) lb0, (off_t) 2048, &lb0_count, 2); if(ret > 0) { has_isolinux_mbr= 1; if(lb0[510] != 0x55 || lb0[511] != 0xaa) has_isolinux_mbr= 0; mbr_lba= lb0[432] | (lb0[433] << 8) | (lb0[434] << 16) | (lb0[435] << 24); mbr_lba/= 4; if(mbr_lba != xorriso->loaded_boot_bin_lba) has_isolinux_mbr= 0; if(has_isolinux_mbr) { for(i= 0; i < 426; i++) if(strncmp((char *) (lb0 + i), "isolinux", 8) == 0) break; if(i >= 426) has_isolinux_mbr= 0; } for(i= 462; i < 510; i++) if(lb0[i]) break; if(i < 510) has_isolinux_mbr= 0; } if(has_isolinux_mbr) strcat(respt, " , ISOLINUX isohybrid MBR pointing to boot image"); else strcat(respt, " , ISOLINUX boot image capable of isohybrid"); } strcat(respt, "\n"); Xorriso_toc_line(xorriso, flag & 8); if(flag & 2) return(1); if(bin_path_valid) sprintf(respt, "Boot bin_path: %s\n", Text_shellsafe(path, sfe, 0)); else if(xorriso->loaded_boot_bin_lba <= 0) sprintf(respt, "Boot bin_path: -not-found-at-load-time-\n"); else sprintf(respt, "Boot bin_path: -not-found-any-more-by-lba=%d\n", xorriso->loaded_boot_bin_lba); Xorriso_toc_line(xorriso, flag & 8); if(xorriso->loaded_boot_cat_path[0]) sprintf(respt, "Boot cat_path: %s\n", Text_shellsafe(xorriso->loaded_boot_cat_path, sfe, 0)); else sprintf(respt, "Boot cat_path: -not-found-at-load-time-\n"); Xorriso_toc_line(xorriso, flag & 8); return(1); } /* @param flag bit1=report about output drive bit3=report to info channel (else to result channel) bit4=do no report failure if no drive aquired */ int Xorriso_media_product(struct XorrisO *xorriso, int flag) { int ret, profile_no; struct burn_drive_info *dinfo; struct burn_drive *drive; char *product_id= NULL, *media_code1= NULL, *media_code2= NULL; char *book_type= NULL, *manuf= NULL, profile_name[80], *respt; respt= xorriso->result_line; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to print media product info", flag & (2 | 16)); if(ret <= 0) return(ret); ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2, &book_type, 0); if(ret > 0) { ret= burn_disc_get_profile(drive, &profile_no, profile_name); if(ret <= 0) return(ret); sprintf(respt, "Media product: %s , ", product_id); manuf= burn_guess_manufacturer(profile_no, media_code1, media_code2, 0); if(manuf != NULL) { if(strncmp(manuf, "Unknown ", 8) == 0) sprintf(respt + strlen(respt), "(not found in manufacturer list)\n"); else sprintf(respt + strlen(respt), "%s\n", manuf); } else sprintf(respt + strlen(respt), "(error during manufacturer lookup)\n"); free(product_id); free(media_code1); free(media_code2); if(book_type != NULL) free(book_type); if(manuf != NULL) free(manuf); Xorriso_toc_line(xorriso, flag & 8); } Xorriso_process_msg_queues(xorriso,0); return(1); } /* @param flag bit0=short report form bit1=report about output drive bit2=do not try to read ISO heads bit3=report to info channel (else to result channel) bit4=do no report failure if no drive aquired bit5=only report "Drive current" and "Drive type" bit6=report "Media product" with bit0 bit7=only report "Drive current" */ int Xorriso_toc(struct XorrisO *xorriso, int flag) { int num_sessions= 0, num_tracks= 0, lba= 0, nwa= -1, pmin, psec, pframe, ret; int track_count= 0, session_no, track_no, profile_no= -1, track_size; int last_track_start= 0, last_track_size= -1, num_data= 0, is_data= 0; int is_inout_drive= 0, drive_role, status, num_formats, emul_lba; int num_payload= 0, num_wasted= 0, num_nondata= 0, not_reconizable= 0; char profile_name[80],*respt,*devadr, *typetext= ""; struct burn_toc_entry toc_entry; struct burn_drive_info *dinfo; struct burn_drive *drive; enum burn_disc_status s; char mem_text[80]; off_t start_byte= 0, num_free= 0, size; unsigned dummy; struct isoburn_toc_disc *disc= NULL; struct isoburn_toc_session **sessions; struct isoburn_toc_track **tracks; int image_blocks= 0; char volume_id[33]; struct burn_toc_entry next_toc_entry; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to print Table Of Content", flag & (2 | 16)); if(ret<=0) {ret= 0; goto ex;} respt= xorriso->result_line; if(strcmp(xorriso->indev, xorriso->outdev)==0) is_inout_drive= 1; if(flag&2) devadr= xorriso->outdev; else devadr= xorriso->indev; sprintf(respt, "Drive current: %s '%s'\n", (is_inout_drive ? "-dev" : (flag&2 ? "-outdev" : "-indev")), devadr); Xorriso_toc_line(xorriso, flag & 8); if(flag & 128) {ret= 1; goto ex;} sprintf(respt, "Drive type : vendor '%s' product '%s' revision '%s'\n", dinfo[0].vendor, dinfo[0].product, dinfo[0].revision); if((flag & 32) | !(flag & 1)) Xorriso_toc_line(xorriso, flag & 8); if(flag & 32) {ret= 1; goto ex;} ret= burn_disc_get_profile(drive, &profile_no, profile_name); s= isoburn_disc_get_status(drive); if(profile_no == 0x0002 && s == BURN_DISC_EMPTY) profile_no= 0; sprintf(respt, "Media current: "); if (profile_no > 0 && ret > 0) { if (profile_name[0]) sprintf(respt+strlen(respt), "%s", profile_name); else sprintf(respt+strlen(respt), "%4.4Xh", profile_no); drive_role= burn_drive_get_drive_role(drive); if(drive_role==2) sprintf(respt+strlen(respt), ", overwriteable"); else if(drive_role==0 || drive_role==3) sprintf(respt+strlen(respt), ", sequential"); strcat(respt, "\n"); } else { sprintf(respt+strlen(respt), "is not recognizable\n"); not_reconizable= 1; } Xorriso_toc_line(xorriso, flag & 8); if((flag & 64) || !(flag & 1)) { Xorriso_media_product(xorriso, flag & (2 | 8 | 16)); if(xorriso->request_to_abort) {ret= 1; goto ex;} } sprintf(respt, "Media status : "); if (s == BURN_DISC_FULL) { if(not_reconizable) sprintf(respt+strlen(respt), "is not recognizable\n"); else sprintf(respt+strlen(respt), "is written , is closed\n"); } else if (s == BURN_DISC_APPENDABLE) { sprintf(respt+strlen(respt), "is written , is appendable\n"); } else if (s == BURN_DISC_BLANK) { sprintf(respt+strlen(respt), "is blank\n"); } else if (s == BURN_DISC_EMPTY) sprintf(respt+strlen(respt), "is not present\n"); else sprintf(respt+strlen(respt), "is not recognizable\n"); Xorriso_toc_line(xorriso, flag & 8); if(s == BURN_DISC_BLANK) { sprintf(respt, "Media summary: 0 sessions, 0 data blocks, 0 data"); num_free= isoburn_disc_available_space(drive, NULL); Sfile_scale((double) num_free, mem_text,5,1e4,1); sprintf(respt+strlen(respt), ", %s free\n", mem_text); Xorriso_toc_line(xorriso, flag & 8); } if(s != BURN_DISC_FULL && s != BURN_DISC_APPENDABLE) {ret= 1; goto ex;} if(xorriso->request_to_abort) {ret= 1; goto ex;} if(!(flag & 2)) Xorriso_show_boot_info(xorriso, 1 | (flag & 8) | ((flag & 1) << 1)); disc= isoburn_toc_drive_get_disc(drive); if(flag & 4) sprintf(respt, "TOC layout : %3s , %9s , %10s\n", "Idx", "sbsector", "Size"); else sprintf(respt, "TOC layout : %3s , %9s , %10s , %s\n", "Idx", "sbsector", "Size", "Volume Id"); if(!(flag&1)) Xorriso_toc_line(xorriso, flag & 8); if (disc==NULL) { Xorriso_process_msg_queues(xorriso,0); ret= isoburn_get_min_start_byte(drive, &start_byte, 0); nwa= start_byte / 2048; if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); if(flag&1) {ret= 0; goto ex;} sprintf(xorriso->info_text, "Cannot obtain Table Of Content"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0); {ret= 0; goto ex;} } /* fabricate TOC */ typetext= "Other session"; if(flag & 4) { ret= 0; typetext= "Session "; } else ret= isoburn_read_iso_head(drive, 0, &image_blocks, volume_id, 1); if(ret>0) { sprintf(respt, "ISO session : %3d , %9d , %9ds , %s\n", 1, 0, image_blocks, volume_id); nwa= image_blocks; } else { nwa= 0; ret= burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats); if(ret>0 && status==BURN_FORMAT_IS_FORMATTED) nwa= size/2048; sprintf(respt, "%13s: %3d , %9d , %9ds , \n", typetext, 1, 0, nwa); } if(!(flag&1)) Xorriso_toc_line(xorriso, flag & 8); last_track_start= lba; num_payload= num_data= last_track_size= nwa; num_sessions= 1; } else { sessions= isoburn_toc_disc_get_sessions(disc, &num_sessions); for (session_no= 0; session_norequest_to_abort); session_no++) { tracks= isoburn_toc_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; isoburn_toc_track_get_entry(tracks[track_no], &toc_entry); if (toc_entry.extensions_valid & 1) { /* DVD extension valid */ lba= toc_entry.start_lba; track_size= toc_entry.track_blocks; } else { lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe); if(track_no==num_tracks-1) { isoburn_toc_session_get_leadout_entry(sessions[session_no], &next_toc_entry); } else { isoburn_toc_track_get_entry(tracks[track_no+1], &next_toc_entry); } track_size= burn_msf_to_lba(next_toc_entry.pmin, next_toc_entry.psec, next_toc_entry.pframe) - lba; } if(flag&(1|4)) ret= 0; else { ret= isoburn_toc_track_get_emul(tracks[track_no], &emul_lba, &image_blocks, volume_id, 0); if(ret <= 0) ret= isoburn_read_iso_head(drive, lba, &image_blocks, volume_id, 1); if(image_blocks > track_size) { sprintf(xorriso->info_text, "Session %d bears ISO image size %ds larger than track size %ds", session_no + 1, image_blocks, track_size); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); image_blocks= track_size; } } if(ret>0 && track_no==0) { sprintf(respt, "ISO session : %3d , %9d , %9ds , %s\n", session_no+1, lba, image_blocks , volume_id); } else if(ret>0) { sprintf(respt, "ISO track : %3d , %9d , %9ds , %s\n", track_count, lba, image_blocks , volume_id); } else if(track_no==0) { typetext= "Other session"; if(flag & 4) typetext= "Session "; sprintf(respt, "%13s: %3d , %9d , %9ds , \n", typetext, session_no+1, lba, track_size); } else { typetext= "Other track "; if(flag & 4) typetext= "Track "; sprintf(respt, "%13s: %3d , %9d , %9ds , \n", typetext, track_count, lba, track_size); } if(!(flag&1)) Xorriso_toc_line(xorriso, flag & 8); if(track_no>0) num_payload+= lba - last_track_start; last_track_start= lba; if((toc_entry.control&7)>=4) /* data track */ is_data= 1; } isoburn_toc_session_get_leadout_entry(sessions[session_no], &toc_entry); if (toc_entry.extensions_valid & 1) { lba= toc_entry.start_lba; burn_lba_to_msf(lba, &pmin, &psec, &pframe); } else { lba= burn_msf_to_lba(pmin, psec, pframe); lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe); } last_track_size= lba - last_track_start; num_payload+= last_track_size; if(is_data) num_data+= last_track_size; } } if(xorriso->request_to_abort) {ret= 1; goto ex;} num_wasted= lba - num_payload; num_nondata= lba - num_data; Sfile_scale(((double) num_data) * 2048.0, mem_text,5,1e4,1); sprintf(respt, "Media summary: %d session%s, %d data blocks, %s data", num_sessions, (num_sessions==1 ? "" : "s"), num_data, mem_text); num_free= isoburn_disc_available_space(drive, NULL); Sfile_scale((double) num_free, mem_text,5,1e4,1); sprintf(respt+strlen(respt), ", %s free", mem_text); sprintf(respt+strlen(respt), "\n"); Xorriso_toc_line(xorriso, flag & 8); if (s==BURN_DISC_APPENDABLE && nwa!=0) { ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa); if(ret>0) { sprintf(respt, "Media nwa : %ds\n", nwa); if(!(flag&1)) Xorriso_toc_line(xorriso, flag & 8); } } if (disc!=NULL) isoburn_toc_disc_free(disc); Xorriso_process_msg_queues(xorriso,0); ret= 1; ex:; return(ret); } int Xorriso_show_devices(struct XorrisO *xorriso, int flag) { char adr[BURN_DRIVE_ADR_LEN]; int i, j, max_dev_len= 1, pad; struct burn_drive_info *drive_list= NULL; unsigned int drive_count; char *respt, perms[8]; struct stat stbuf; sprintf(xorriso->info_text, "Beginning to scan for devices ...\n"); Xorriso_info(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); sprintf(xorriso->info_text, "-----------------------------------------------------------------------------\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(strlen(adr)>max_dev_len) max_dev_len= strlen(adr); } 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' ", i, adr); pad= max_dev_len-strlen(adr); if(pad>0) for(j= 0; jinfo_text, "-----------------------------------------------------------------------------\n"); Xorriso_info(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 bit2= do not re-aquire drive @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]; time_t start_time; char mode_names[4][80]= {"all", "fast", "deformat", "deformat_quickest"}; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); 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); /* Important: do not return until burn_is_aborting() was checked */ Xorriso_set_signal_handling(xorriso, 1); if(do_deformat) burn_disc_erase(drive, (flag&1)); else isoburn_disc_erase(drive, (flag&1)); start_time= time(0); usleep(1000000); while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) { Xorriso_process_msg_queues(xorriso,0); 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 in %d seconds )", percent, (int) (time(0) - start_time)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0); usleep(1000000); } Xorriso_process_msg_queues(xorriso,0); if(burn_is_aborting(0)) Xorriso_abort(xorriso, 0); /* Never comes back */ Xorriso_set_signal_handling(xorriso, 0); if(burn_drive_wrote_well(drive)) { sprintf(xorriso->info_text, "Blanking done\n"); Xorriso_info(xorriso,0); } else { sprintf(xorriso->info_text, "Blanking failed."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } if(!(flag & 4)) { ret= Xorriso_reaquire_outdev(xorriso, 2 + (xorriso->in_drive_handle == xorriso->out_drive_handle)); if(ret <= 0) return(-1); } return(1); } /* @param flag bit0= try to achieve faster formatting bit1= use parameter size (else use default size) bit2= do not re-aquire drive bit7= by_index mode: bit8 to bit15 contain the index of the format to use. @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, off_t in_size, int flag) { int ret, mode_flag= 0, index, status, num_formats; unsigned dummy; struct burn_drive_info *dinfo; struct burn_drive *drive; struct burn_progress p; double percent = 1.0; int current_profile; char current_profile_name[80]; off_t size= 0; time_t start_time; enum burn_disc_status disc_state; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to -format", 2); if(ret<=0) return(0); if(flag & 2) { mode_flag= 0; /* format to given size */ } else { mode_flag= 4; /* format to full size */ } burn_disc_get_profile(drive, ¤t_profile, current_profile_name); if(flag&128) { /* by_index */ index= (flag>>8) & 0xff; ret= burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats); if(ret<=0) num_formats= 0; if(ret<=0 || index<0 || index>=num_formats) { if(num_formats>0) sprintf(xorriso->info_text, "-format by_index_%d: format descriptors range from index 0 to %d", index, num_formats-1); else sprintf(xorriso->info_text, "-format by_index_%d: no format descriptors available", index); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } mode_flag|= (flag & 0xff80); if(flag&1) mode_flag|= (1<<6); } else if(current_profile == 0x12) { /* DVD+RAM */ if(!(flag & 2)) mode_flag= 6; /* format to default payload size */ if(flag&1) mode_flag|= (1<<6); } else if(current_profile == 0x13) { /* DVD-RW */ if(flag&1) { sprintf(xorriso->info_text, "Detected formatted DVD-RW. Thus omitting desired fast format run."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(2); } } else if(current_profile == 0x14) { /* DVD-RW sequential */ if(flag & 1) { size= 128*1024*1024; mode_flag= 1; /* format to size, then write size of zeros */ } else mode_flag= 4; } else if(current_profile == 0x1a) { /* DVD+RW */ if(flag&1) { sprintf(xorriso->info_text, "Detected DVD+RW. Thus omitting desired fast format run."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(2); } } else if(current_profile == 0x41) { /* BD-R SRM */ if(!(flag & 2)) mode_flag= 6; /* format to default payload size */ if(flag&1) mode_flag|= (1<<6); } else if(current_profile == 0x43) { /* BD-RE */ if(!(flag & 2)) mode_flag= 6; /* format to default payload size */ if(flag&1) mode_flag|= (1<<6); } else { sprintf(xorriso->info_text, "-format: Unsuitable media detected."); 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(!(flag & 1)) mode_flag|= 16; /* enable re-formatting */ 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); if(flag & 2) size= in_size; /* Important: do not return until burn_is_aborting() was checked */ Xorriso_set_signal_handling(xorriso, 1); burn_disc_format(drive, size, mode_flag); start_time= time(0); usleep(1000000); while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) { Xorriso_process_msg_queues(xorriso,0); 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, "Formatting ( %.1f%% done in %d seconds )", percent, (int) (time(0) - start_time)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0); usleep(1000000); } Xorriso_process_msg_queues(xorriso,0); if(burn_is_aborting(0)) Xorriso_abort(xorriso, 0); /* Never comes back */ Xorriso_set_signal_handling(xorriso, 0); if(burn_drive_wrote_well(drive)) { sprintf(xorriso->info_text, "Formatting done\n"); Xorriso_info(xorriso,0); } else { sprintf(xorriso->info_text, "libburn indicates failure with formatting."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(-1); } if(!(flag & 4)) { ret= Xorriso_reaquire_outdev(xorriso, 2 + (xorriso->in_drive_handle == xorriso->out_drive_handle)); if(ret <= 0) return(-1); } disc_state = isoburn_disc_get_status(drive); if(disc_state==BURN_DISC_FULL && !(flag&1)) { /* Blank because full format certification pattern might be non-zero */ ret= Xorriso_blank_media(xorriso, 1); if(ret <= 0) return(0); } return(1); } /* @param flag bit2= formatting rather than blanking @return 0=failure, did not touch media , -1=failure, altered media 1=success, altered media , 2=success, did not touch media */ int Xorriso_blank_as_needed(struct XorrisO *xorriso, int flag) { int ret, is_formatted= -1, status, num_formats, did_work= 0; struct burn_drive_info *dinfo; struct burn_drive *drive; enum burn_disc_status disc_state; unsigned dummy; int current_profile; char current_profile_name[80]; off_t size; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to blank or format", 2); if(ret<=0) return(0); burn_disc_get_profile(drive, ¤t_profile, current_profile_name); ret= burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats); if(ret>0) { if(status==BURN_FORMAT_IS_FORMATTED) is_formatted= 1; else if(status == BURN_FORMAT_IS_UNFORMATTED) is_formatted= 0; } if(current_profile == 0x12 || current_profile == 0x43) { /* DVD+RAM , BD-RE */ if(is_formatted<0) { sprintf(xorriso->info_text, "-blank or -format: Unclear formatting status of %s", current_profile_name); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } if(!is_formatted) { ret= Xorriso_format_media(xorriso, (off_t) 0, (current_profile == 0x43)); if(ret <= 0) return(ret); did_work= (ret == 1); } } else if(current_profile == 0x14 && (flag&4)) { /* DVD-RW sequential */ ret= Xorriso_format_media(xorriso, (off_t) 0, 0); if(ret <= 0) return(ret); did_work= (ret == 1); } else if(current_profile == 0x41) { /* BD-R SRM */ if(!is_formatted) { ret= Xorriso_format_media(xorriso, (off_t) 0, 1); if(ret <= 0) return(ret); did_work= (ret == 1); } } disc_state = isoburn_disc_get_status(drive); if(disc_state != BURN_DISC_BLANK && !(flag&4)) { ret= Xorriso_blank_media(xorriso, 1); return(ret); } if(did_work) return(1); sprintf(xorriso->info_text, "%s as_needed: no need for action detected", (flag&4) ? "-format" : "-blank"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(2); } /* @return <=0 error, 1 success */ int Xorriso_list_formats(struct XorrisO *xorriso, int flag) { int ret, i, status, num_formats, profile_no, type; off_t size; unsigned dummy; char status_text[80], profile_name[90], *respt; struct burn_drive_info *dinfo; struct burn_drive *drive; respt= xorriso->result_line; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to obtain format descriptor list", 1 | 2); if(ret<=0) return(0); if(ret == 2) goto ex; ret = burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats); if(ret<=0) { sprintf(xorriso->info_text, "Cannot obtain format list info"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } ret= Xorriso_toc(xorriso, 3); if(ret<=0) goto ex; ret= burn_disc_get_profile(drive, &profile_no, profile_name); if(ret<=0) goto ex; if(status == BURN_FORMAT_IS_UNFORMATTED) sprintf(status_text, "unformatted, up to %.1f MiB", ((double) size) / 1024.0 / 1024.0); else if(status == BURN_FORMAT_IS_FORMATTED) { if(profile_no==0x12 || profile_no==0x13 || profile_no==0x1a || profile_no==0x43) sprintf(status_text, "formatted, with %.1f MiB", ((double) size) / 1024.0 / 1024.0); else sprintf(status_text, "written, with %.1f MiB", ((double) size) / 1024.0 / 1024.0); } else if(status == BURN_FORMAT_IS_UNKNOWN) { if (profile_no > 0) sprintf(status_text, "intermediate or unknown"); else sprintf(status_text, "no media or unknown media"); } else sprintf(status_text, "illegal status according to MMC-5"); sprintf(respt, "Format status: %s\n", status_text); Xorriso_result(xorriso,0); for (i= 0; i < num_formats; i++) { ret= burn_disc_get_format_descr(drive, i, &type, &size, &dummy); if (ret <= 0) continue; sprintf(respt, "Format idx %-2d: %2.2Xh , %.fs , %.1f MiB\n", i, type, ((double) size) / 2048.0, ((double) size) / 1024.0/1024.0); Xorriso_result(xorriso,0); } ret= 1; ex:; return(ret); } /* @param flag bit0= cdrecord style bit1= obtain outdrive, else indrive @return <=0 error, 1 success */ int Xorriso_list_profiles(struct XorrisO *xorriso, int flag) { int ret, i; struct burn_drive_info *dinfo; struct burn_drive *drive; int num_profiles, profiles[64]; char is_current[64], profile_name[90], *respt; respt= xorriso->result_line; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to obtain profile list", 1 | (flag & 2)); if(ret<=0) return(0); burn_drive_get_all_profiles(drive, &num_profiles, profiles, is_current); for(i= 0; i < num_profiles; i++) { ret= burn_obtain_profile_name(profiles[i], profile_name); if(ret <= 0) strcpy(profile_name, "unknown"); sprintf(respt, "%s 0x%4.4X (%s)%s\n", flag & 1 ? "Profile:" : "Profile :", (unsigned int) profiles[i], profile_name, is_current[i] ? " (current)" : ""); Xorriso_result(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) { int ret; int lba1= 0, lba2= 0; ret= Xorriso__file_start_lba(*((IsoNode **) node1), &lba1, 0); if(ret!=1) lba1= 0; ret= Xorriso__file_start_lba(*((IsoNode **) node2), &lba2, 0); if(ret!=1) lba2= 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 bit6= do not delete eventually existing node from di_array @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= 0, node_idx; /* 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;} } #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 | 64)) | 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; } } if(!(flag & 64)) Xorriso_invalidate_di_item(xorriso, victim_node, 0); #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_set_change_pending(xorriso, 0); ret= 1+!!is_dir; ex:; if(sfe!=NULL) free(sfe); if(sub_path!=NULL) free(sub_path); 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; 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;} } *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:; if(sfe!=NULL) free(sfe); if(path!=NULL) free(path); if(show_path!=NULL) free(show_path); if(iter!=NULL) iso_dir_iter_free(iter); if(node_array!=NULL) free((char *) node_array); Xorriso_process_msg_queues(xorriso,0); return(ret); } 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) | 16); 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 */ iso_node_get_acl_text(node, &a_text, &d_text, 16); ret= Xorriso_format_ls_l(xorriso, &stbuf, 1 | ((a_text != NULL || d_text != NULL) << 1)); iso_node_get_acl_text(node, &a_text, &d_text, 1 << 15); 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, 1); 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; char *adr= NULL; adr= malloc(SfileadrL); if(adr==NULL) { Xorriso_no_malloc_memory(xorriso, &adr, 0); {ret= -1; goto ex;} } 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:; if(adr!=NULL) free(adr); if(flag&2) (*dive_count)--; if(iter != NULL) iso_dir_iter_free(iter); 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", (unsigned int) (mode & 0xffff), Text_shellsafe(path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); Xorriso_set_change_pending(xorriso, 0); 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_set_change_pending(xorriso, 0); 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_set_change_pending(xorriso, 0); 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_set_change_pending(xorriso, 0); Xorriso_process_msg_queues(xorriso,0); return(1); } int Xorriso__start_end_lbas(IsoNode *node, int *lba_count, int **start_lbas, int **end_lbas, off_t *size, int flag) { int section_count= 0, ret, i; struct iso_file_section *sections= NULL; *lba_count= 0; *start_lbas= *end_lbas= NULL; *size= 0; if(!LIBISO_ISREG(node)) return(0); *size= iso_file_get_size((IsoFile *) node); ret= iso_file_get_old_image_sections((IsoFile *) node, §ion_count, §ions, 0); if(ret < 0) {ret= -1; goto ex;} if(ret != 1 || section_count <= 0) {ret= 0; goto ex;} *start_lbas= calloc(section_count, sizeof(int)); *end_lbas= calloc(section_count, sizeof(int)); if(*start_lbas == NULL || *end_lbas == NULL) {ret= -1; goto ex;} for(i= 0; i < section_count; i++) { (*start_lbas)[i]= sections[i].block; (*end_lbas)[i]= sections[i].block + sections[i].size / 2048 - 1; if(sections[i].size % 2048) (*end_lbas)[i]++; } *lba_count= section_count; ret= 1; ex:; if(sections != NULL) free((char *) sections); if(ret <= 0) { if((*start_lbas) != NULL) free((char *) *start_lbas); if((*end_lbas) != NULL) free((char *) *end_lbas); *start_lbas= *end_lbas= NULL; *lba_count= 0; } return(ret); } int Xorriso__file_start_lba(IsoNode *node, int *lba, int flag) { int *start_lbas= NULL, *end_lbas= NULL, lba_count= 0, i, ret; off_t size; *lba= -1; ret= Xorriso__start_end_lbas(node, &lba_count, &start_lbas, &end_lbas, &size, 0); if(ret <= 0) return(ret); for(i= 0; i < lba_count; i++) { if(*lba < 0 || start_lbas[i] < *lba) *lba= start_lbas[i]; } if(start_lbas != NULL) free((char *) start_lbas); if(end_lbas != NULL) free((char *) end_lbas); if(*lba < 0) return(0); return(1); } /* @param damage_start Returns first damaged byte address @param damage_end Returns first byte address after last damaged byte @return <0 error, 0=undamaged , 1=damaged */ int Xorriso_file_eval_damage(struct XorrisO *xorriso, IsoNode *node, off_t *damage_start, off_t *damage_end, int flag) { int *start_lbas= NULL, *end_lbas= NULL, lba_count= 0, sect; int i, sectors, sector_size, ret; off_t sect_base= 0, size= 0, byte; struct SectorbitmaP *map; *damage_start= *damage_end= -1; map= xorriso->in_sector_map; if(map == NULL) return(0); Sectorbitmap_get_layout(map, §ors, §or_size, 0); sector_size/= 2048; ret= Xorriso__start_end_lbas(node, &lba_count, &start_lbas, &end_lbas, &size, 0); if(ret <= 0) { Xorriso_process_msg_queues(xorriso, 0); return(ret); } for(sect= 0; sect < lba_count; sect++) { for(i= start_lbas[sect]; i <= end_lbas[sect]; i+= sector_size) { if(Sectorbitmap_is_set(map, i / sector_size, 0) == 0) { byte= ((off_t) 2048) * ((off_t) (i - start_lbas[sect])) + sect_base; if(*damage_start < 0 || byte < *damage_start) *damage_start= byte; if(byte + (off_t) 2048 > *damage_end) *damage_end= byte + (off_t) 2048; } } sect_base+= ((off_t) 2048) * ((off_t) (end_lbas[sect] - start_lbas[sect] + 1)); } if(*damage_end > size) *damage_end= size; if(start_lbas != NULL) free((char *) start_lbas); if(end_lbas != NULL) free((char *) end_lbas); if(*damage_start < 0) return(0); return(1); } int Xorriso_report_lba(struct XorrisO *xorriso, char *show_path, IsoNode *node, int flag) { int ret, *start_lbas= NULL, *end_lbas= NULL, lba_count, i; off_t size; char sfe[5*SfileadrL]; ret= Xorriso__start_end_lbas(node, &lba_count, &start_lbas, &end_lbas, &size, 0); if(ret < 0) { Xorriso_process_msg_queues(xorriso, 0); {ret= -1; goto ex;} } if(ret == 0) {ret= 1; goto ex;} /* it is ok to ignore other types */ for(i= 0; i < lba_count; i++) { sprintf(xorriso->result_line, "File data lba: %2d , %8d , %8d , %8.f , %s\n", i, start_lbas[i], end_lbas[i] + 1 - start_lbas[i], (double) size, Text_shellsafe(show_path, sfe, 0)); Xorriso_result(xorriso, 0); } ret= 1; ex:; if(start_lbas != NULL) free((char *) start_lbas); if(end_lbas != NULL) free((char *) end_lbas); return(ret); } int Xorriso_report_damage(struct XorrisO *xorriso, char *show_path, IsoNode *node, int flag) { int ret; off_t size= 0, damage_start, damage_end; char sfe[5*SfileadrL]; ret= Xorriso_file_eval_damage(xorriso, node, &damage_start, &damage_end, 0); if(ret < 0) return(0); if(LIBISO_ISREG(node)) size= iso_file_get_size((IsoFile *) node); if(ret > 0) { sprintf(xorriso->result_line, "File damaged : %8.f , %8.f , %8.f , %s\n", (double) damage_start, (double) (damage_end - damage_start) , (double) size, Text_shellsafe(show_path, sfe, 0)); Xorriso_result(xorriso, 0); } else { sprintf(xorriso->result_line, "File seems ok: %8.f , %8.f , %8.f , %s\n", -1.0, -1.0, (double) size, Text_shellsafe(show_path, sfe, 0)); Xorriso_result(xorriso, 0); } return(1); } /* @return see Xorriso_update_interpreter() */ int Xorriso_widen_hardlink(struct XorrisO *xorriso, void * boss_iter, IsoNode *node, char *abs_path, char *iso_prefix, char *disk_prefix, int flag) { int ret= 0, idx, low, high, i, do_widen= 0, compare_result= 0; char disk_path[SfileadrL]; /* Lookup all di_array instances of node */ if(LIBISO_ISDIR(node)) return(3); ret= Xorriso_search_di_range(xorriso, node, &idx, &low, &high, 2); if(ret <= 0) return(3); /* Check and reset di_do_widen bits */ for(i= low; i <= high; i++) { if(node != xorriso->di_array[i]) /* might be NULL */ continue; if(xorriso->di_do_widen[i / 8] & (1 << (i % 8))) do_widen= 1; xorriso->di_do_widen[i / 8]&= ~(1 << (i % 8)); } if(idx < 0 || !do_widen) return(3); ret= Xorriso_pfx_disk_path(xorriso, abs_path, iso_prefix, disk_prefix, disk_path, 0); if(ret <= 0) return(ret); ret= Sfile_type(disk_path, 1); if(ret < 0) return(3); /* does not exist on disk */ /* >>> compare_result bit17 = is_split */; ret= Xorriso_update_interpreter(xorriso, boss_iter, compare_result, disk_path, abs_path, 1); if(ret <= 0) return(ret); return(ret); } /* Apply the effect of mkisofs -r to a single node */ int Xorriso_mkisofs_lower_r(struct XorrisO *xorriso, IsoNode *node, int flag) { mode_t perms; perms= iso_node_get_permissions(node); iso_node_set_uid(node, (uid_t) 0); iso_node_set_gid(node, (gid_t) 0); perms|= S_IRUSR | S_IRGRP | S_IROTH; perms&= ~(S_IWUSR | S_IWGRP | S_IWOTH); if(perms & (S_IXUSR | S_IXGRP | S_IXOTH)) perms|= (S_IXUSR | S_IXGRP | S_IXOTH); perms&= ~(S_ISUID | S_ISGID | S_ISVTX); iso_node_set_permissions(node, perms); 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, *text_2, sfe[5*SfileadrL], *iso_prefix, md5[16]; struct FindjoB *subjob; struct stat dir_stbuf; action= Findjob_get_action_parms(job, &target, &text_2, &user, &group, &mode_and, &mode_or, &type, &date, &subjob, 0); if(action<0) action= 0; hflag= 16*!(flag&2); ret= 1; 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 if(action == 21) { /* report_damage */ ret= Xorriso_report_damage(xorriso, show_path, node, 0); } else if(action == 22) { ret= Xorriso_report_lba(xorriso, show_path, node, 0); } else if(action == 23) { /* internal: memorize path of last matching node */ ret= Findjob_set_found_path(job, show_path, 0); } else if(action == 24) { ret= Xorriso_getfacl(xorriso, (void *) node, show_path, NULL, 0); } else if(action == 25) { if(target == NULL || target[0] || text_2 == NULL || text_2[0]) ret= Xorriso_setfacl(xorriso, (void *) node, show_path, target, text_2,0); } else if(action == 26) { ret= Xorriso_getfattr(xorriso, (void *) node, show_path, NULL, 0); } else if(action == 27) { ret= Xorriso_path_setfattr(xorriso, (void *) node, show_path, target, strlen(text_2), text_2, 0); } else if(action == 28) { /* set_filter */ ret= Xorriso_set_filter(xorriso, (void *) node, show_path, target, 1 | 2); } else if(action == 29) { /* show_stream */ ret= Xorriso_show_stream(xorriso, (void *) node, show_path, 1 | 2); } else if(action == 30) { /* internal: count */ xorriso->node_counter++; } else if(action == 31) { /* internal: register */ if(xorriso->node_counter < xorriso->node_array_size) { xorriso->node_array[xorriso->node_counter++]= (void *) node; iso_node_ref(node); /* In case node gets deleted from tree during the lifetime of xorriso->node_array */ } } else if(action == 32) { /* internal: widen_hardlinks disk_equiv */ Findjob_get_start_path(job, &iso_prefix, 0); ret= Xorriso_widen_hardlink(xorriso, (void *) boss_iter, node, abs_path, iso_prefix, target, 0); if(ret==2) deleted= 1; } else if(action == 33) { /* get_any_xattr */ ret= Xorriso_getfattr(xorriso, (void *) node, show_path, NULL, 8); } else if(action == 34) { /* get_md5 */ ret= Xorriso_get_md5(xorriso, (void *) node, show_path, md5, 0); if(ret >= 0) ret= 1; } else if(action == 35) { /* check_md5 */ ret= Xorriso_check_md5(xorriso, (void *) node, show_path, 2); if(ret == 0) xorriso->find_check_md5_result|= 1; else if(ret < 0) xorriso->find_check_md5_result|= 2; else if(ret == 1) xorriso->find_check_md5_result|= 8; else if(ret == 2) xorriso->find_check_md5_result|= 4; if(ret >= 0) ret= 1; } else if(action == 36) { /* make_md5 */ ret= Xorriso_make_md5(xorriso, (void *) node, show_path, 0); if(ret >= 0) ret= 1; } else if(action == 37) { /* mkisofs_r */ ret= Xorriso_mkisofs_lower_r(xorriso, node, 0); } else if(action == 38) { /* sort_weight */ iso_node_set_sort_weight(node, type); } 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); } int Exprtest_match(struct XorrisO *xorriso, struct ExprtesT *ftest, void *node_pt, char *name, char *path, struct stat *boss_stbuf, struct stat *stbuf, int flag) /* return: <0 = error 0 = does not match 1 = does match 2 = immediate decision : does not match 3 = immediate decision : does match */ { int value=0, ret, start_lba, end_lba; int lba_count, *file_end_lbas= NULL, *file_start_lbas= NULL, i; void *arg1, *arg2; char ft, *decision, md5[16]; regmatch_t name_match; off_t damage_start, damage_end, size; void *xinfo_dummy; IsoNode *node; IsoStream *stream; if(ftest == NULL) return(1); node= (IsoNode *) node_pt; arg1= ftest->arg1; arg2= ftest->arg2; if(node == NULL) { if(ftest->test_type > 2 && ftest->test_type != 4) { value= 0; goto ex; } } switch(ftest->test_type) { case 0: /* -false */ value= 0; break; case 1: /* -name *arg1 (regex in *arg2) */ ret= regexec(arg2, name, 1, &name_match, 0); value= !ret; break; case 2: /* -type *arg1 */ value= 1; ft= *((char *) arg1); if(ft!=0) { if(S_ISBLK(stbuf->st_mode)) { if(ft!='b') value= 0; } else if(S_ISCHR(stbuf->st_mode)) { if(ft!='c') value= 0; } else if(S_ISDIR(stbuf->st_mode)) { if(ft=='m') { if(node != NULL) value= 0; else if(boss_stbuf==NULL) value= 0; else if(boss_stbuf->st_dev == stbuf->st_dev) value= 0; } else if(ft!='d') value= 0; } else if(S_ISFIFO(stbuf->st_mode)) { if(ft!='p') value= 0; } else if(S_ISREG(stbuf->st_mode)) { if(ft!='f' && ft!='-') value= 0; } else if(((stbuf->st_mode)&S_IFMT)==S_IFLNK) { if(ft!='l') value= 0; } else if(((stbuf->st_mode)&S_IFMT)==S_IFSOCK) { if(ft!='s') value= 0; } else if((flag & 1) && ((stbuf->st_mode) & S_IFMT) == Xorriso_IFBOOT) { if(ft!='e' || node == NULL) value= 0; } else { if(ft!='X') value= 0; } } break; case 3: /* -damaged */; value= Xorriso_file_eval_damage(xorriso, node, &damage_start, &damage_end, 0); if(value > 0) value= 1; break; case 4: /* -lba_range *arg1 *arg2 */ value= 1; start_lba= *((int *) ftest->arg1); end_lba= *((int *) ftest->arg2); if(node == NULL) { value= !(start_lba >= 0); goto ex; } ret= Xorriso__start_end_lbas(node, &lba_count, &file_start_lbas, &file_end_lbas, &size, 0); if(ret <= 0) { if(ret < 0) Xorriso_process_msg_queues(xorriso, 0); if(start_lba >= 0) value= 0; } else { for(i= 0; i < lba_count; i++) { if(start_lba >= 0) { if(file_end_lbas[i] < start_lba || file_start_lbas[i] > end_lba) value= 0; } else { if(file_end_lbas[i] >= -start_lba && file_start_lbas[i] <= -end_lba) value= 0; } } } break; case 5: /* -has_acl */ ret = Xorriso_getfacl(xorriso, (void *) node, "", NULL, 2); if(ret <= 0) { value= -1; Xorriso_process_msg_queues(xorriso, 0); goto ex; } value= (ret == 1); break; case 6: /* -has_xattr */ case 14: /* -has_any_xattr */ ret = Xorriso_getfattr(xorriso, (void *) node, "", NULL, 64 | (8 * (ftest->test_type == 14))); if(ret < 0) { value= -1; Xorriso_process_msg_queues(xorriso, 0); goto ex; } value= (ret > 0); break; case 7: /* -has_aaip */ ret= iso_node_get_xinfo(node, aaip_xinfo_func, &xinfo_dummy); if(ret < 0) { value= -1; Xorriso_process_msg_queues(xorriso, 0); goto ex; } value= (ret > 0); break; case 8: /* -has_filter */ value= 0; if(LIBISO_ISREG(node)) { stream= iso_file_get_stream((IsoFile *) node); if(iso_stream_get_input_stream(stream, 0) != NULL) value= 1; } break; case 9: /* -wanted_node arg1 (for internal use) */ value= (((IsoNode *) arg1) == node); break; case 10: /* -pending_data */ value= 1; if(!LIBISO_ISREG(node)) { value= 0; } else { ret= Xorriso__file_start_lba(node, &start_lba, 0); if(ret > 0 && start_lba >= 0) value= 0; } break; case 11: /* -decision */ value= 2; decision= (char *) arg1; if(strcmp(decision, "yes") == 0 || strcmp(decision, "true") == 0) value= 3; break; case 12: /* -prune */ value= 1; ftest->boss->prune= 1; break; case 13: /* -wholename *arg1 (regex in *arg2) */ ret= regexec(arg2, path, 1, &name_match, 0); value= !ret; break; case 15: /* -has_md5 */ ret= Xorriso_get_md5(xorriso, node, path, md5, 1); value= (ret > 0); break; default: /* >>> complain about unknown test type */; value= -1; } ex:; if(ftest->invert && value<=1 && value>=0) value= !value; if(file_start_lbas != NULL) free((char *) file_start_lbas); if(file_end_lbas != NULL) free((char *) file_end_lbas); return(value); } /* @return <0 = error , 0 = no match , 1 = match */ int Xorriso_findi_test(struct XorrisO *xorriso, struct FindjoB *job, IsoNode *node, char *name, char *path, struct stat *boss_stbuf, struct stat *stbuf, int depth, int flag) { int ret; job->prune= 0; ret= Findjob_test_2(xorriso, job, node, name, path, boss_stbuf, stbuf, 1); if(ret <= 0) return(ret); return(1); } int Xorriso_findi_headline(struct XorrisO *xorriso, struct FindjoB *job, int flag) { int action; action= Findjob_get_action(job, 0); if(action == 21) { /* report_damage */ sprintf(xorriso->result_line, "Report layout: %8s , %8s , %8s , %s\n", "at byte", "Range", "Filesize", "ISO image path"); Xorriso_result(xorriso, 0); } else if(action == 22) { /* report_lba */ sprintf(xorriso->result_line, "Report layout: %2s , %8s , %8s , %8s , %s\n", "xt", "Startlba", "Blocks", "Filesize", "ISO image path"); Xorriso_result(xorriso, 0); } return(1); } /* @param flag bit0= recursion bit1= do not count deleted files with rm and rm_r bit2= do not dive into split file directories (implicitly given with actions 14=compare and 17=update) @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= NULL; struct stat stbuf; char *name; off_t mem; IsoNode **node_array= NULL; int node_count, node_idx; char *path= NULL, *abs_path= NULL; if(xorriso->request_to_abort) {ret= 0; goto ex;} path= malloc(SfileadrL); abs_path= malloc(SfileadrL); if(path==NULL || abs_path==NULL) { Xorriso_no_malloc_memory(xorriso, &path, 0); {ret= -1; goto ex;} } action= Findjob_get_action(job, 0); if(action<0) action= 0; if(!(flag & 1)) Xorriso_findi_headline(xorriso, job, 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); if(ret<=0) goto ex; name= strrchr(dir_path, '/'); if(name==NULL) name= dir_path; else name++; ret= Xorriso_findi_test(xorriso, job, iso_node, name, path, NULL, dir_stbuf, depth, 0); if(ret<0) goto ex; if(job->prune) no_dive= 1; if(ret>0) { iso_node_ref(iso_node); /* protect from real disposal */ ret= Xorriso_findi_action(xorriso, job, (IsoDirIter *) boss_iter, boss_mem, path, dir_path, iso_node, depth, flag&(1|2)); deleted= (iso_node_get_parent(iso_node) == NULL); /* still in tree ? */ iso_node_unref(iso_node); /* eventually do real disposal */ if(ret<=0) goto ex; if(xorriso->request_to_abort) {ret= 0; goto ex;} if(ret==2 || deleted) { /* re-determine dir_node in case it has a new persona */ ret= Xorriso_node_from_path(xorriso, volume, path, &iso_node, 1); if(ret==0) { deleted= 1; {ret= 2; goto ex;} } if(ret<0) {ret= 0; goto ex;} dir_node= (IsoDir *) iso_node; ret= Xorriso_fake_stbuf(xorriso, "", dir_stbuf, &iso_node, 1); if(ret<=0) goto ex; } if(ret==3) no_dive= 1; } } if(no_dive || !LIBISO_ISDIR((IsoNode *) dir_node)) {ret= 1; goto ex;} if(action == 14 || action == 17 || (flag & 4)) if(Xorriso_is_split(xorriso, dir_path, (IsoNode *) dir_node, 1)>0) {ret= 1; goto ex;} mem= boss_mem; hflag= 1; if(action==1 || action==2 || action==3 || action==17 || action == 28 || action == 32) hflag|= 2; /* need freedom to manipulate image */ if(action==14 || action==17 || action == 28 || action == 35 || action == 36) 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) 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= Xorriso_findi_test(xorriso, job, node, name, path, dir_stbuf, &stbuf, depth, 0); if(ret<0) goto ex; if(job->prune) no_dive= 1; 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(xorriso->request_to_abort) {ret= 0; goto ex;} if(ret==2) { /* node has been deleted */ /* re-determine node in case it has a new persona */ if(volume==NULL) { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) {ret= -1; goto ex;} } ret= Xorriso_node_from_path(xorriso, volume, abs_path, &node, 1); if(ret==0) continue; if(ret<0) {ret= 0; goto ex;} ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1); if(ret<0) goto ex; if(ret==0) 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:; if(path!=NULL) free(path); if(abs_path!=NULL) free(abs_path); 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); } int Xorriso_node_is_valid(struct XorrisO *xorriso, IsoNode *in_node, int flag) { IsoNode *node, *parent; for(node= in_node; 1; node= parent) { parent= (IsoNode *) iso_node_get_parent(node); if(parent == node) break; if(parent == NULL) return(0); /* Node is not in the tree (any more) */ } return(1); } int Xorriso_path_from_node(struct XorrisO *xorriso, IsoNode *in_node, char path[SfileadrL], int flag) { int ret, i, comp_count= 0; IsoNode *node, *parent, **components= NULL; char *wpt, *npt; for(node= in_node; 1; node= parent) { parent= (IsoNode *) iso_node_get_parent(node); if(parent == node) break; if(parent == NULL) return(0); /* Node is not in the tree (any more) */ comp_count++; } if(comp_count == 0) { strcpy(path, "/"); return(1); } components= calloc(comp_count, sizeof(IsoNode *)); if(components == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } i= comp_count; for(node= in_node; 1; node= parent) { parent= (IsoNode *) iso_node_get_parent(node); if(parent == node) break; components[--i]= node; } wpt= path; for(i= 0; i < comp_count; i++) { npt= (char *) iso_node_get_name(components[i]); if((wpt - path) + strlen(npt) + 1 >= SfileadrL) { /* >>> path is getting much too long */; ret= -1; goto ex; } *(wpt++)= '/'; strcpy(wpt, npt); wpt+= strlen(npt); *wpt= 0; } ret= 1; ex:; if(components != NULL) free(components); return(ret); } /* <<< The lookup from node pointer will be done by Xorriso_path_from_node() (Currently it runs a full tree traversal) Parameter node and flag bit0 will vanish then */ /* @param flag bit0= use lba rather than node pointer */ int Xorriso_path_from_lba(struct XorrisO *xorriso, IsoNode *node, int lba, char path[SfileadrL], int flag) { int ret; struct FindjoB *job= NULL; struct stat dir_stbuf; char *found_path; path[0]= 0; if((flag & 1) && lba <= 0) return(0); ret= Findjob_new(&job, "/", 0); if(ret <= 0) { Xorriso_no_findjob(xorriso, "path_from_node", 0); return(ret); } if(flag & 1) Findjob_set_lba_range(job, lba, 1, 0); else Findjob_set_wanted_node(job, (void *) node, 0); Findjob_set_action_found_path(job, 0); ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/", &dir_stbuf, 0, 0); if(ret > 0) { ret= 1; Findjob_get_found_path(job, &found_path, 0); if(found_path == NULL) ret= 0; else if(Sfile_str(path, found_path, 0) <= 0) ret= -1; } Findjob_destroy(&job, 0); return(ret); } /* @param flag bit0= do not dive into trees bit1= do not perform job->action on resulting node array bit2= do not free node_array after all actions are done */ int Xorriso_findi_sorted(struct XorrisO *xorriso, struct FindjoB *job, off_t boss_mem, int filec, char **filev, int flag) { int i, ret, find_flag= 0; struct FindjoB array_job, *proxy_job= NULL, *hindmost= NULL, *hmboss= NULL; struct stat dir_stbuf; IsoNode *node; char abs_path[SfileadrL]; off_t mem_needed= 0; array_job.start_path= NULL; if(job->action == 14 || job->action == 17) find_flag|= 4; if(job->action>=9 && job->action<=13) { /* actions which have own findjobs */ /* array_job replaces the hindmost job in the chain */ for(hindmost= job; hindmost->subjob != NULL; hindmost= hindmost->subjob) hmboss= hindmost; if(hmboss == NULL) {ret= -1; goto ex;} memcpy(&array_job, hindmost, sizeof(struct FindjoB)); hmboss->subjob= &array_job; proxy_job= job; } else { memcpy(&array_job, job, sizeof(struct FindjoB)); proxy_job= &array_job; hindmost= job; } array_job.start_path= NULL; /* is owned by the original, not by array_job */ /* Count matching nodes */ Xorriso_destroy_node_array(xorriso, 0); array_job.action= 30; /* internal: count */ for(i= 0; i < filec; i++) { if(flag & 1) { xorriso->node_counter++; continue; } ret= Findjob_set_start_path(proxy_job, filev[i], 0); if(ret <= 0) goto ex; ret= Xorriso_findi(xorriso, proxy_job, NULL, boss_mem, NULL, filev[i], &dir_stbuf, 0, find_flag); if(ret <= 0) goto ex; } if(xorriso->node_counter <= 0) {ret= 1; goto ex;} mem_needed= boss_mem + xorriso->node_counter * sizeof(IsoNode *); if(!(flag &1)) { ret= Xorriso_check_temp_mem_limit(xorriso, mem_needed, 0); if(ret <= 0) { /* Memory curbed : Perform unsorted find jobs */ if(hmboss != NULL) hmboss->subjob= hindmost; for(i= 0; i < filec; i++) { ret= Findjob_set_start_path(job, filev[i], 0); if(ret <= 0) goto ex; ret= Xorriso_findi(xorriso, job, NULL, boss_mem, NULL, filev[i], &dir_stbuf, 0, find_flag); if(ret <= 0) if(Xorriso_eval_problem_status(xorriso, ret, 1|2)<0) goto ex; } {ret= 1; goto ex;} } } /* Copy matching nodes into allocated array */ ret= Xorriso_new_node_array(xorriso, xorriso->temp_mem_limit, 0, 0); if(ret <= 0) goto ex; array_job.action= 31; /* internal: register */ xorriso->node_counter= 0; for(i= 0; i < filec; i++) { if(flag & 1) { ret= Xorriso_get_node_by_path(xorriso, filev[i], NULL, &node, 0); if(ret <= 0) goto ex; if(xorriso->node_counter < xorriso->node_array_size) { xorriso->node_array[xorriso->node_counter++]= (void *) node; iso_node_ref(node); } continue; } ret= Findjob_set_start_path(proxy_job, filev[i], 0); if(ret <= 0) goto ex; ret= Xorriso_findi(xorriso, proxy_job, NULL, mem_needed, NULL, filev[i], &dir_stbuf, 0, find_flag); if(ret <= 0) goto ex; } Xorriso_sort_node_array(xorriso, 0); if(flag & 2) {ret= 1; goto ex;} /* Perform job->action on xorriso->node_array */ /* Headlines of actions report_damage , report_lba */; Xorriso_findi_headline(xorriso, job, 0); for(i= 0; i < xorriso->node_counter; i++) { node= xorriso->node_array[i]; ret= Xorriso_path_from_node(xorriso, node, abs_path, 0); if(ret < 0) goto ex; if(ret == 0) continue; /* node is deleted from tree meanwhile */ ret= Xorriso_findi_action(xorriso, hindmost, NULL, (off_t) 0, abs_path, abs_path, node, 0, 1); if(ret <= 0 || xorriso->request_to_abort) if(Xorriso_eval_problem_status(xorriso, ret, 1|2)<0) goto ex; } ret= 1; ex:; if(!(flag & (2 | 4))) Xorriso_destroy_node_array(xorriso, 0); if(hmboss != NULL) hmboss->subjob= hindmost; if(array_job.start_path != NULL) free(array_job.start_path); return(ret); } /* @param flag bit0= do not mark image as changed */ int Xorriso_set_volid(struct XorrisO *xorriso, char *volid, int flag) { int ret; IsoImage *volume; if(xorriso->in_volset_handle == NULL) return(2); ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(ret); iso_image_set_volume_id(volume, volid); if(!(flag&1)) Xorriso_set_change_pending(xorriso, 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=prepare for a burn run */ int Xorriso_set_abort_severity(struct XorrisO *xorriso, int flag) { int ret, abort_on_number; char *sev_text; static int note_number= -1, failure_number= -1; if(note_number==-1) Xorriso__text_to_sev("NOTE", ¬e_number, 0); if(failure_number==-1) Xorriso__text_to_sev("FAILURE", &failure_number, 0); sev_text= xorriso->abort_on_text; ret= Xorriso__text_to_sev(xorriso->abort_on_text, &abort_on_number, 0); if(ret<=0) return(ret); if(abort_on_numberfailure_number) sev_text= "FAILURE"; ret= iso_set_abort_severity(sev_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); strcpy(xorriso->result_line, "libburn OS adapter: "); strncat(xorriso->result_line, burn_scsi_transport_id(0), 1024); strcat(xorriso->result_line, "\n"); 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; char *manuf= NULL, *media_code1= NULL, *media_code2= NULL; char *book_type= NULL, *product_id= NULL; 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); Xorriso_list_profiles(xorriso, 1 | 2); if(strstr(profile_name,"BD")==profile_name) { printf("Mounted Media: %2.2Xh, %s\n", profile_number, profile_name); } else if(strstr(profile_name,"DVD")==profile_name) { sprintf(respt, "book type: %s (emulated booktype)\n", profile_name); Xorriso_result(xorriso,1); if(profile_number == 0x13) { 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); } ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2, &book_type, 0); if(ret > 0 && media_code1 != NULL && media_code2 != NULL) manuf= burn_guess_manufacturer(profile_number, media_code1, media_code2, 0); if(product_id != NULL) { sprintf(respt, "Product Id: %s\n", product_id); Xorriso_result(xorriso,1); } if(manuf != NULL) { sprintf(respt, "Producer: %s\n", manuf); Xorriso_result(xorriso, 1); } if(profile_number == 0x09 || profile_number == 0x0a) { sprintf(respt, "Manufacturer: %s\n", manuf); Xorriso_result(xorriso, 1); } else if(product_id != NULL && media_code1 != NULL && media_code2 != NULL){ free(product_id); free(media_code1); free(media_code2); if(book_type != NULL) free(book_type); product_id= media_code1= media_code2= book_type= NULL; ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2, &book_type, 1); if(ret > 0) { sprintf(respt, "Manufacturer: '%s'\n", media_code1); Xorriso_result(xorriso, 1); if(media_code2[0]) { sprintf(respt, "Media type: '%s'\n", media_code2); Xorriso_result(xorriso, 1); } } } if(manuf != NULL) free(manuf); if(media_code1 != NULL) free(media_code1); if(media_code2 != NULL) free(media_code2); if(book_type != NULL) free(book_type); if(product_id != NULL) free(product_id); return(1); } int Xorriso_update_in_sector_map(struct XorrisO *xorriso, struct SpotlisT *spotlist, int read_chunk, struct CheckmediajoB *job, int flag) { int sectors, sector_size, sector_blocks, ret; struct SectorbitmaP *map; Sectorbitmap_destroy(&(xorriso->in_sector_map), 0); if(job->use_dev == 1) return(1); map= job->sector_map; sectors= Spotlist_block_count(spotlist, 0); if(sectors <= 0) return(0); sector_size= Spotlist_sector_size(spotlist, read_chunk, 0); sector_blocks= sector_size / 2048; if(sector_blocks > 1) sectors= sectors / sector_blocks + !!(sectors % sector_blocks); ret= Sectorbitmap_new(&(xorriso->in_sector_map), sectors, sector_size, 0); if(ret <= 0) return(ret); if(map != NULL) Sectorbitmap_copy(map, xorriso->in_sector_map, 0); ret= Xorriso_spotlist_to_sectormap(xorriso, spotlist, read_chunk, &(xorriso->in_sector_map), 1); return(ret); } /* @param flag bit0= obtain iso_lba from indev bit1= head_buffer already contains a valid head bit2= issue message about success bit3= check whether source blocks are banned by in_sector_map */ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, char *head_buffer, struct CheckmediajoB *job, int flag) { int ret, full_size, i; char *headpt; struct burn_drive_info *dinfo; struct burn_drive *drive; off_t seek_ret; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); if(flag & 1) { ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to learn current session lba", 1); if(ret<=0) return(0); ret= isoburn_disc_get_msc1(drive, &iso_lba); if(ret<=0) return(0); drive= NULL; /* indev will not be used furtherly */ } if(job == NULL) { ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to update at lba 0 to 31", 2); if(ret<=0) return(0); } if(iso_lba < 32) return(2); if(!(flag & 2)) { /* head_buffer was not filled yet. Read it from output media. */ if(job != NULL && job->data_to_fd >= 0) { if((flag & 8) && job->sector_map != NULL) { ret= Sectorbitmap_bytes_are_set(job->sector_map, ((off_t) iso_lba) * (off_t) 2048, ((off_t) (iso_lba + 32)) * ((off_t) 2048) - (off_t) 1, 0); if(ret <= 0) { sprintf(xorriso->info_text, "ISO image head at lba %d is marked as invalid blocks in file copy", iso_lba); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); return(0); } } seek_ret= lseek(job->data_to_fd, ((off_t) 2048) * (off_t) iso_lba, SEEK_SET); if(seek_ret == -1) ret= 0; else ret= read(job->data_to_fd, head_buffer, 64 * 1024); if(ret < 64 * 1024) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot read ISO image head from file copy"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); return(0); } } else { ret= isoburn_read_iso_head(drive, iso_lba, &isosize, head_buffer, 2); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot read freshly written ISO image head"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } } } /* patch ISO header */ full_size= iso_lba + isosize; headpt= head_buffer + 32*1024; for(i=0;i<4;i++) headpt[87-i]= headpt[80+i]= (full_size >> (8*i)) & 0xff; if(job != NULL) { seek_ret= lseek(job->data_to_fd, (off_t) 0, SEEK_SET); if(seek_ret == -1) ret= 0; else ret= write(job->data_to_fd, head_buffer, 64 * 1024); if(ret < 64 * 1024) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot write ISO image head to file copy"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); return(0); } } else { ret= burn_random_access_write(drive, (off_t) 0, head_buffer, (off_t) (64*1024), 1); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot write new ISO image head to LBA 0"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } } if(flag & 4) { sprintf(xorriso->info_text, "Overwrote LBA 0 to 31 by 64 KiB from LBA %d", iso_lba); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); } return(1); } /* @param write_start_address is valid if >=0 @param tsize is valid if >0 @param flag bit0= grow_overwriteable_iso bit1= do_isosize bit2= do_xa1 conversion */ int Xorriso_burn_track(struct XorrisO *xorriso, off_t write_start_address, char *track_source, off_t tsize, int flag) { int ret, fd, unpredicted_size, profile_number, is_cd= 0, dummy, nwa= -1; int isosize= -1, do_isosize, is_bd= 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= NULL, *fifo_src= NULL; enum burn_disc_status disc_state; char reasons[BURN_REASONS_LEN], sfe[5*SfileadrL], profile_name[80]; char head_buffer[64*1024]; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) return(0); ret= Xorriso_auto_format(xorriso, 0); if(ret <=0 ) return(0); do_isosize= !!(flag&2); 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) { sprintf(xorriso->info_text, "Cannot add session object to disc object."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); goto ex; } track= burn_track_create(); if(track_source[0] == '-' && track_source[1] == 0) { fd= 0; } else { if(xorriso->fs >= 64) fd= burn_os_open_track_src(track_source, O_RDONLY, 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; 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; } if((do_isosize || xorriso->fs != 0) && xorriso->fs < 64) xorriso->fs= 64; if(xorriso->fs > 0) { fifo_src= burn_fifo_source_new(data_src, 2048 + 8 * !!(flag & 4), xorriso->fs, 1); if(fifo_src == NULL) { sprintf(xorriso->info_text, "Could not create fifo object of %.f MB", ((double) xorriso->fs) / 1024.0 / 1024.0); 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 == NULL ? data_src : 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_track_set_cdxa_conv(track, !!(flag & 4)); burn_session_add_track(session, track, BURN_POS_END); burn_source_free(data_src); if(flag&1) /* consider overwriteables with ISO as appendable */ disc_state= isoburn_disc_get_status(drive); else /* handle overwriteables as always blank */ disc_state= burn_disc_get_status(drive); if(disc_state == BURN_DISC_BLANK || disc_state == BURN_DISC_APPENDABLE) { /* ok */; } else { if(disc_state == BURN_DISC_FULL) { sprintf(xorriso->info_text, "Closed media with data detected. Need blank or appendable media."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); if(burn_disc_erasable(drive)) { sprintf(xorriso->info_text, "Try -blank as_needed\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(isoburn_needs_emulation(drive)) burn_write_opts_set_multi(burn_options, 0); if(tsize > 0) { fixed_size= tsize; burn_track_set_size(track, fixed_size); } if(do_isosize) { ret= burn_fifo_peek_data(xorriso->pacifier_fifo, head_buffer, 64*1024, 0); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot obtain first 64 kB from input stream."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } /* read isosize from head_buffer, not from media*/ ret= isoburn_read_iso_head(drive, 0, &isosize, head_buffer, (1<<13)); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Option -isosize given but data stream seems not to be ISO 9660"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } sprintf(xorriso->info_text, "Size of ISO 9660 image: %ds", isosize); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); fixed_size= ((off_t) (isosize)) * (off_t) 2048; burn_track_set_size(track, fixed_size); } ret= Xorriso_get_profile(xorriso, &profile_number, profile_name, 2); is_cd= (ret==2); is_bd= (ret == 3); if(isoburn_needs_emulation(drive)) { if(flag&1) { ret= isoburn_disc_track_lba_nwa(drive, burn_options, 0, &dummy, &nwa); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot obtain next writeable address of emulated multi-session media\n"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } if(nwa==32) nwa= 0; /* No automatic toc emulation. Formatter might not be aware. */ burn_write_opts_set_start_byte(burn_options,((off_t) nwa) * (off_t) 2048); } else { nwa= 0; burn_write_opts_set_start_byte(burn_options, (off_t) 0); } } if(write_start_address>=0) { nwa= write_start_address / (off_t) 2048; if(((off_t) nwa) * (off_t) 2048 < write_start_address ) nwa++; burn_write_opts_set_start_byte(burn_options, ((off_t) nwa) * (off_t) 2048); } 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_sanitize_image_size(xorriso, drive, disc, burn_options, 2); if(ret<=0) goto ex; /* Important: do not return until burn_is_aborting() was checked */ Xorriso_set_signal_handling(xorriso, 1); xorriso->run_state= 1; /* Indicate that burning has started */ burn_disc_write(burn_options, disc); ret= Xorriso_pacifier_loop(xorriso, drive, 2 | (is_cd << 4) | (is_bd << 5)); if(burn_is_aborting(0)) Xorriso_abort(xorriso, 0); /* Never comes back */ Xorriso_set_signal_handling(xorriso, 0); 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; } if(flag & 1) { ret= Xorriso_update_iso_lba0(xorriso, nwa, isosize, head_buffer, NULL, flag & 2); if(ret <= 0) goto ex; } sprintf(xorriso->info_text, "Writing to %s completed sucessfully.\n\n", Text_shellsafe(xorriso->outdev,sfe,0)); 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 3= ok, is BD 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(((flag&2) && xorriso->out_drive_handle==NULL) || ((!(flag&2)) && xorriso->in_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); if(*profile_number == 0x40 || *profile_number == 0x41 || *profile_number == 0x42 || *profile_number == 0x43) return(3); return(0); } int Xorriso_iso_file_open(struct XorrisO *xorriso, char *pathname, void *node_pt, void **stream, int flag) { int ret; char eff_path[SfileadrL]; IsoNode *node= NULL; IsoFile *filenode= NULL; IsoStream *iso_stream= NULL, *input_stream; *stream= NULL; if(flag&1) { node= (IsoNode *) node_pt; } else { 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); } 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); } if(flag & 2) { /* Dig out the most original stream */ while(1) { input_stream= iso_stream_get_input_stream(iso_stream, 0); if(input_stream == NULL) break; iso_stream= input_stream; } } 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); 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); } Xorriso_process_msg_queues(xorriso,0); *stream= iso_stream; #ifdef NIX /* <<< */ { unsigned int fs_id; dev_t dev_id; ino_t ino; iso_stream_get_id(iso_stream, &fs_id, &dev_id, &ino); fprintf(stderr, "xorriso_debug: iso_ino= %ld\n", (long int) ino); } #endif 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(rcntsplit_size <= 0 */ int Xorriso_identify_split(struct XorrisO *xorriso, char *iso_adr, void *in_node, struct SplitparT **parts, int *count, struct stat *total_stbuf, int flag) { int ret, i, incomplete= 0, overlapping= 0; int partno, total_parts, first_total_parts= -1; off_t offset, bytes, total_bytes, first_total_bytes= -1, first_bytes= -1; off_t size, covered; IsoImage *volume; IsoDir *dir_node; IsoDirIter *iter= NULL; IsoNode *node; char *name; struct stat stbuf, first_stbuf; *count= 0; *parts= NULL; if(xorriso->split_size <= 0 && !(flag & 4)) return(0); if(flag&1) { node= (IsoNode *) in_node; } else { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(-1); ret= Xorriso_node_from_path(xorriso, volume, iso_adr, &node, 1); if(ret<=0) return(-1); } if(!LIBISO_ISDIR(node)) return(0); dir_node= (IsoDir *) node; ret= iso_dir_get_children(dir_node, &iter); if(ret<0) { cannot_iter:; Xorriso_cannot_create_iter(xorriso, ret, 0); return(-1); } for(i= 0; iso_dir_iter_next(iter, &node) == 1; i++) { name= (char *) iso_node_get_name(node); ret= Splitpart__parse(name, &partno, &total_parts, &offset, &bytes, &total_bytes, 0); if(ret<=0) {ret= 0; goto ex;} if(i==0) { first_total_parts= total_parts; first_bytes= bytes; first_total_bytes= total_bytes; Xorriso_fake_stbuf(xorriso, "", &first_stbuf, &node, 1); size= first_stbuf.st_size; } else { if(first_total_parts!=total_parts || first_total_bytes!=total_bytes || (first_bytes!=bytes && partno!=total_parts)) {ret= 0; goto ex;} Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1); if(first_stbuf.st_mode != stbuf.st_mode || first_stbuf.st_uid != stbuf.st_uid || first_stbuf.st_gid != stbuf.st_gid || first_stbuf.st_mtime != stbuf.st_mtime || first_stbuf.st_ctime != stbuf.st_ctime) {ret= 0; goto ex;} size= stbuf.st_size; } /* check for plausible size */ if(!((partno != total_parts && size == bytes) || (partno == total_parts && size <= bytes))) {ret= 0; goto ex;} if(offset != first_bytes * (off_t) (partno - 1)) {ret= 0; goto ex;} (*count)++; } if(*count <= 0 || *count != first_total_parts) {ret= 0; goto ex;} ret= Splitparts_new(parts, (*count)+1, 0); /* (have one end marker item) */ if(ret<=0) return(ret); iso_dir_iter_free(iter); ret= iso_dir_get_children(dir_node, &iter); if(ret<0) goto cannot_iter; for(i= 0; i<*count; i++) { ret= iso_dir_iter_next(iter, &node); if(ret!=1) break; name= (char *) iso_node_get_name(node); ret= Splitpart__parse(name, &partno, &total_parts, &offset, &bytes, &total_bytes, 0); if(ret<=0) {ret= 0; goto ex;} ret= Splitparts_set(*parts, i, name, partno, total_parts, offset, bytes, total_bytes, 0); if(ret<=0) goto ex; } Splitparts_sort(*parts, *count, 0); covered= 0; for(i= 0; i<*count; i++) { Splitparts_get(*parts, i, &name, &partno, &total_parts, &offset, &bytes, &total_bytes, 0); if(offset>covered) incomplete= 1; else if(offset covered) covered= offset+bytes; } if(total_bytes>covered) incomplete= 1; memcpy(total_stbuf, &first_stbuf, sizeof(struct stat)); total_stbuf->st_size= total_bytes; ret= !(overlapping || incomplete); ex:; if(iter!=NULL) iso_dir_iter_free(iter); return(ret); } /* @param flag bit0= node is valid, do not resolve path bit1= insist in complete collection of part files */ int Xorriso_is_split(struct XorrisO *xorriso, char *path, void *node, int flag) { struct SplitparT *split_parts= NULL; int split_count= 0, ret; struct stat stbuf; ret= Xorriso_identify_split(xorriso, path, node, &split_parts, &split_count, &stbuf, flag & 3); if(split_parts!=NULL) Splitparts_destroy(&split_parts, split_count, 0); return(ret>0); } /* @param flag bit0= grow_overwriteable_iso bit1= obtain info from outdev bit2= no need to obtain msc2 (NWA) */ int Xorriso_msinfo(struct XorrisO *xorriso, int *msc1, int *msc2, int flag) { int ret, dummy; struct burn_drive *drive; struct burn_drive_info *dinfo; enum burn_disc_status disc_state; *msc1= *msc2= -1; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to obtain msinfo", flag&2); if(ret<=0) return(ret); if(flag&1) disc_state= isoburn_disc_get_status(drive); else disc_state= burn_disc_get_status(drive); if(disc_state != BURN_DISC_APPENDABLE && !(disc_state == BURN_DISC_FULL && (flag & 4))) { Xorriso_process_msg_queues(xorriso,0); if(!(flag & 4)) { sprintf(xorriso->info_text, "%s media is not appendable. Cannot obtain -msinfo.", (flag&2) ? "Output" : "Input"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } return(0); } ret= isoburn_disc_get_msc1(drive, msc1); if(ret<=0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot obtain address of most recent session"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } if(flag & 4) return(1); ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &dummy, msc2); if(ret<0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Cannot obtain next writeable address on media"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } return(1); } /* @param flag bit0= this is a follow-up session (i.e. on CD: TAO) bit1= no pacifier messages bit2= compute stream MD5 and look out for checksum tag @return <=0 error, 1= done, 2= aborted due to limit */ int Xorriso_check_interval(struct XorrisO *xorriso, struct SpotlisT *spotlist, struct CheckmediajoB *job, int from_lba, int block_count, int read_chunk, int md5_start, int flag) { int i, j, ret, total_count= 0, sectors= -1, sector_size= -1, skip_reading; int prev_quality= -1, quality= -1, retry= 0, profile_no, is_cd= 0; int start_sec, end_sec, first_value, fret; char profile_name[80]; int start_lba= 0; struct burn_drive *drive; struct burn_drive_info *dinfo; char data[64*1024], sfe[5*SfileadrL]; off_t data_count, to_read, read_count= 0, write_amount; double pre_read_time, post_read_time, time_diff, total_time_diff= 0; double last_abort_file_time= 0; struct stat stbuf; void *ctx= NULL, *cloned_ctx= NULL; char md5[16], tag_md5[16]; uint32_t pos, range_start, range_size, next_tag= 0, lba, md5_spot_lba= 0; int md5_spot_value= Xorriso_read_quality_untesteD, chain_broken= 0; int tag_type= 0, valid, was_sb_tag= 0, in_track_gap= 0; char *comparison= "", *sev_text= "DEBUG", *tag_type_name= ""; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to check media readability", 2 * !!job->use_dev); if(ret<=0) goto ex; ret= burn_disc_get_profile(drive, &profile_no, profile_name); if(ret > 0) if(profile_no >= 0x08 && profile_no <= 0x0a) is_cd= 1; if(job->sector_map != NULL) { Sectorbitmap_get_layout(job->sector_map, §ors, §or_size, 0); sector_size/= 2048; } if(job->retry > 0) retry= 1; else if(job->retry == 0 && is_cd) retry= 1; if(flag & 4) { ret= iso_md5_start(&ctx); if(ret < 0) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } } start_lba= from_lba; to_read= read_chunk; post_read_time= Sfile_microtime(0); for(i= 0; i < block_count; i+= to_read) { skip_reading= 0; if(job->abort_file_path[0]) { if(post_read_time - last_abort_file_time >= 0.1) { if(stat(job->abort_file_path, &stbuf) != -1) { if(stbuf.st_mtime >= xorriso->start_time) { sprintf(xorriso->info_text, "-check_media: Found fresh abort_file=%s", job->abort_file_path); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); goto abort_check; } } last_abort_file_time= post_read_time; } } if(job->item_limit > 0 && Spotlist_count(spotlist, 0) + 2 >= job->item_limit) { sprintf(xorriso->info_text, "-check_media: Reached item_limit=%d", job->item_limit); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); goto abort_check; } pre_read_time= Sfile_microtime(0); if(job->time_limit > 0 && job->start_time + job->time_limit < pre_read_time) { sprintf(xorriso->info_text, "-check_media: Reached time_limit=%d", job->time_limit); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); abort_check:; if(prev_quality >= 0) { ret= Spotlist_add_item(spotlist, start_lba, i + from_lba - start_lba, prev_quality, 0); if(ret <= 0) goto ex; } ret= Spotlist_add_item(spotlist, i + from_lba, block_count - i, Xorriso_read_quality_untesteD, 0); if(ret > 0) ret= 2; goto ex; } to_read= read_chunk; if(i + to_read > block_count) to_read= block_count - i; if(is_cd && i + to_read + 2 >= block_count) { /* Read last 2 blocks of CD track separately, because with TAO tracks they are always unreadable but with SAO tracks they contain data. */ if(to_read > 2) to_read-= 2; else if(to_read > 1) { if(flag & 1) { quality= Xorriso_read_quality_tao_enD; skip_reading= 1; } else to_read--; } } if(sector_size == read_chunk && from_lba % read_chunk == 0 && !skip_reading) { if(Sectorbitmap_is_set(job->sector_map, (i + from_lba) / sector_size, 0)){ quality= Xorriso_read_quality_valiD; skip_reading= 1; } } else if(sector_size > 0 && !skip_reading) { start_sec= (i + from_lba) / sector_size; end_sec= (i + to_read + from_lba) / sector_size; first_value= Sectorbitmap_is_set(job->sector_map, start_sec, 0); for(j= start_sec; j < end_sec; j++) if(Sectorbitmap_is_set(job->sector_map, j, 0) != first_value) break; to_read= j * sector_size - i - from_lba; skip_reading= !!first_value; if(skip_reading) quality= Xorriso_read_quality_valiD; } if(skip_reading) { pre_read_time= post_read_time= Sfile_microtime(0); } else { data_count= 0; pre_read_time= Sfile_microtime(0); ret= burn_read_data(drive, ((off_t) (i + from_lba)) * (off_t) 2048, data, to_read * (off_t) 2048, &data_count, 4 * !retry); post_read_time= Sfile_microtime(0); time_diff= post_read_time - pre_read_time; total_time_diff+= time_diff; total_count++; if(ret <= 0) { Xorriso_process_msg_queues(xorriso,0); if(data_count / 2048 < to_read) { if(data_count > 0 && retry) { if(prev_quality >= 0) { ret= Spotlist_add_item(spotlist, start_lba, i + from_lba - start_lba, prev_quality, 0); if(ret <= 0) goto ex; } ret= Spotlist_add_item(spotlist, i + from_lba, data_count / 2048, Xorriso_read_quality_partiaL, 0); if(ret <= 0) goto ex; start_lba= i + from_lba + data_count / 2048; prev_quality= Xorriso_read_quality_unreadablE; } quality= Xorriso_read_quality_unreadablE; if(retry) to_read= data_count / 2048 + 1; } else quality= Xorriso_read_quality_partiaL; fret= Xorriso_eval_problem_status(xorriso, ret, 1|2); if(fret<0) goto ex; } else { quality= Xorriso_read_quality_gooD; if(time_diff > job->slow_threshold_seq && job->slow_threshold_seq > 0 && i > 0) quality= Xorriso_read_quality_sloW; } /* MD5 checksumming */ if(ctx != NULL) { for(j= 0; j < to_read; j++) { lba= i + j + from_lba; if(lba < md5_start) continue; ret= 0; if(lba > md5_start + 16 && (next_tag == 0 || chain_broken || lba == next_tag)) { ret= iso_util_decode_md5_tag(data + j * 2048, &tag_type, &pos, &range_start, &range_size, &next_tag, tag_md5, !!chain_broken); } valid= (ret == 1 || ret == ISO_MD5_AREA_CORRUPTED) && pos == lba; if(valid && tag_type == 2 && (lba < md5_start + 32 || in_track_gap)) { tag_type_name= "superblock"; was_sb_tag= 1; if(in_track_gap && range_start != md5_start && range_start < lba && lba - range_start <= j) { /* Looking for next session : start computing in hindsight. Session start and superblock tag are supposed to be in the same 64 kB chunk. */ iso_md5_end(&ctx, md5); ret= iso_md5_start(&ctx); if(ret < 0) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } iso_md5_compute(&ctx, data + (j - (lba - range_start)) * 2048, (lba - range_start) * 2048); md5_start= range_start; in_track_gap= 0; } } else if(valid && tag_type == 4 && lba < 32) { tag_type_name= "relocated 64kB superblock"; }else if(valid && tag_type == 3 && was_sb_tag) { tag_type_name= "tree"; }else if(valid && tag_type == 1) { /* >>> ??? allow this without superblock and tree tag ? */ tag_type_name= "session"; } else { tag_type_name= ""; } if (tag_type_name[0]) { if(range_start != md5_start) { sprintf(xorriso->info_text, "Found MD5 %s tag which covers different data range", tag_type_name); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE",0); sprintf(xorriso->info_text, " Expected: %u Found: %u", (unsigned int) md5_start, range_start); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE",0); chain_broken= 1; valid= 0; } else { ret= iso_md5_clone(ctx, &cloned_ctx); if(ret <= 0) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } iso_md5_end(&cloned_ctx, md5); if(ret == ISO_MD5_AREA_CORRUPTED) { comparison= "CORRUPTED"; sev_text= "WARNING"; md5_spot_value= Xorriso_read_quality_md5_mismatcH; chain_broken= 1; } else if(! iso_md5_match(tag_md5, md5)) { comparison= "NON-MATCHING"; sev_text= "WARNING"; md5_spot_value= Xorriso_read_quality_md5_mismatcH; chain_broken= 1; } else { comparison= "matching"; sev_text= "UPDATE"; md5_spot_value= Xorriso_read_quality_md5_matcH; } md5_spot_lba= lba; sprintf(xorriso->info_text, "Found %s MD5 %s tag: start=%d size=%d", comparison, tag_type_name, md5_start, lba - md5_start); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, sev_text, 0); } if(valid && (tag_type == 1 || (tag_type == 4 && pos == lba && lba < 32))) { if(md5_spot_value != Xorriso_read_quality_untesteD) { ret= Spotlist_add_item(spotlist, md5_start, md5_spot_lba - md5_start, md5_spot_value, 0); if(ret <= 0) goto ex; } md5_spot_value= Xorriso_read_quality_untesteD; md5_start = lba + 1; if (md5_start % 32) md5_start= md5_start + (32 - (md5_start % 32)); next_tag= 0; iso_md5_end(&ctx, md5); ret= iso_md5_start(&ctx); if(ret < 0) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } if(tag_type == 1) in_track_gap= 1; continue; } } iso_md5_compute(ctx, data + j * 2048, 2048); } } write_amount= data_count; if(data_count > 0) { read_count+= data_count; if(job->data_to_limit >= 0 && read_count > job->data_to_limit) write_amount-= (read_count - job->data_to_limit); } if(write_amount > 0) { if(job->data_to_fd >= 0) { ret= lseek(job->data_to_fd, ((off_t) (i + from_lba)) * (off_t) 2048 + job->data_to_offset, SEEK_SET); if(ret == -1) { failed_to_write:; sprintf(xorriso->info_text, "Cannot write %d bytes to lba %d of %s", (int) data_count, i + from_lba, Text_shellsafe(job->data_to_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); {ret= 0; goto ex;} } ret= write(job->data_to_fd, data, write_amount); if(ret == -1) goto failed_to_write; } } } if(quality != prev_quality) { if(prev_quality >= 0) { ret= Spotlist_add_item(spotlist, start_lba, i + from_lba - start_lba, prev_quality, 0); if(ret <= 0) goto ex; } start_lba= i + from_lba; prev_quality= quality; } if(!(flag & 2)) { xorriso->pacifier_count+= to_read; if(post_read_time - xorriso->last_update_time >= xorriso->pacifier_interval) Xorriso_pacifier_callback(xorriso, "sectors examined", xorriso->pacifier_count, xorriso->pacifier_total, "", 0); } } if(prev_quality >= 0) { ret= Spotlist_add_item(spotlist, start_lba, block_count + from_lba - start_lba, prev_quality, 0); if(ret <= 0) goto ex; } /* <<< for calibration of quality */ if(total_count > 0) { sprintf(xorriso->info_text, "Xorriso_check_interval: %.1f s / %d = %f", total_time_diff, total_count, total_time_diff / total_count); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); } /* MD5 checksumming : register result */ /* >>> ??? allow chain_broken to be a match ? */ if(next_tag > 0) { sprintf(xorriso->info_text, "Missing announced MD5 tag: start=%d pos=%d", md5_start, next_tag); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); md5_spot_value= Xorriso_read_quality_md5_mismatcH; md5_spot_lba= next_tag; } if(md5_spot_value != Xorriso_read_quality_untesteD) { ret= Spotlist_add_item(spotlist, md5_start, md5_spot_lba - md5_start, md5_spot_value, 0); if(ret <= 0) goto ex; } ret= 1; ex: if(ctx != NULL) iso_md5_end(&ctx, md5); return(ret); } int Xorriso_check_media(struct XorrisO *xorriso, struct SpotlisT **spotlist, struct CheckmediajoB *job, int flag) { int media_blocks= 0, read_chunk= 16, ret, mode, start_lba= 0; int blocks, os_errno, i, j, last_track_end= -1, track_blocks, track_lba; int num_sessions, num_tracks, declare_untested= 0, md5_start; int read_capacity= -1, end_lba, hret, count, quality; char *toc_info= NULL; struct burn_drive *drive; struct burn_drive_info *dinfo; struct isoburn_toc_disc *isoburn_disc= NULL; struct isoburn_toc_session **isoburn_sessions; struct isoburn_toc_track **iso_burn_tracks; struct burn_toc_entry isoburn_entry; struct stat stbuf; struct burn_multi_caps *caps= NULL; *spotlist= NULL; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to check media readability", 2 * !!job->use_dev); if(ret<=0) goto ex; /* >>> determine media type dependent blocking factor: 32 kB for CD (with 2kB retry) and DVD, 64 kB for BD eventually adjust read_chunk */; if(job->min_block_size != 0) read_chunk= job->min_block_size; ret= Spotlist_new(spotlist, 0); if(ret <= 0) {ret= -1; goto ex;} if(job->sector_map_path[0]) { Sectorbitmap_destroy(&(job->sector_map), 0); if(stat(job->sector_map_path, &stbuf) != -1) { ret= Sectorbitmap_from_file(&(job->sector_map), job->sector_map_path, xorriso->info_text, &os_errno, 0); if(ret <= 0) { if(xorriso->info_text[0]) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, os_errno, "FAILURE", 0); goto ex; } } Xorriso_toc_to_string(xorriso, &toc_info, 4 * !job->map_with_volid); } ret= Xorriso_open_job_data_to(xorriso, job, 0); if(ret <= 0) goto ex; Xorriso_pacifier_reset(xorriso, 0); job->start_time= time(NULL); mode= job->mode; if(job->min_lba > 0) { start_lba= job->min_lba; ret= Spotlist_add_item(*spotlist, 0, job->min_lba, Xorriso_read_quality_untesteD, 0); if(ret <= 0) goto ex; } ret= burn_get_read_capacity(drive, &read_capacity, 0); if(ret <= 0) read_capacity= -1; if(job->max_lba >= 0) { blocks= job->max_lba + 1 - start_lba; xorriso->pacifier_total= blocks; ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks, read_chunk, 0, 0); if(ret <= 0) goto ex; } else if(mode == 0) { /* track by track */ isoburn_disc= isoburn_toc_drive_get_disc(drive); if(isoburn_disc == NULL) goto no_content_visible; isoburn_sessions= isoburn_toc_disc_get_sessions(isoburn_disc, &num_sessions); for(i= 0; i < num_sessions; i++) { iso_burn_tracks= isoburn_toc_session_get_tracks(isoburn_sessions[i], &num_tracks); for(j= 0; j < num_tracks; j++) { isoburn_toc_track_get_entry(iso_burn_tracks[j], &isoburn_entry); if(!(isoburn_entry.extensions_valid & 1)) /* should not happen */ continue; track_lba= isoburn_entry.start_lba; track_blocks= isoburn_entry.track_blocks; md5_start= track_lba; if(i == 0 && j == 0) { if(track_lba == 32) { ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0); if(ret > 0) { if(caps->start_adr) { /* block 0 to 31 are the overall mount entry of overwriteable */ track_lba= 0; track_blocks+= 32; } } } } if(last_track_end >= 0 && last_track_end < track_lba && last_track_end >= start_lba) { ret= Spotlist_add_item(*spotlist, last_track_end, track_lba - last_track_end, Xorriso_read_quality_off_tracK, 0); if(ret <= 0) goto ex; xorriso->pacifier_count+= track_lba - last_track_end; } last_track_end= track_lba + track_blocks; if(track_lba < start_lba) { track_blocks-= start_lba - track_lba; track_lba= start_lba; } if(track_blocks <= 0) continue; if(declare_untested) { ret= Spotlist_add_item(*spotlist, track_lba, track_blocks, Xorriso_read_quality_untesteD, 0); if(ret <= 0) goto ex; } else { ret= Xorriso_check_interval(xorriso, *spotlist, job, track_lba, track_blocks, read_chunk, md5_start, (i > 0) | (4 * (xorriso->do_md5 & 1))); if(ret <= 0) goto ex; if(ret == 2) declare_untested= 1; } } } } else if(mode == 1) { /* isoburn disc capacity */ isoburn_disc= isoburn_toc_drive_get_disc(drive); if(isoburn_disc == NULL) { no_content_visible:; Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "No content detected on media"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } blocks= media_blocks= isoburn_toc_disc_get_sectors(isoburn_disc); if(start_lba >= 0) blocks-= start_lba; if(media_blocks <= 0) goto no_content_visible; xorriso->pacifier_total= blocks; ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks, read_chunk, 0, 0); if(ret <= 0) goto ex; } else if(mode == 2) { /* >>> single sweep over libburn media capacity */; } Xorriso_pacifier_callback(xorriso, "sectors examined", xorriso->pacifier_count, xorriso->pacifier_total, "", 1); ret= 1; ex:; if(job->data_to_fd != -1) close(job->data_to_fd); job->data_to_fd= -1; if(read_capacity >= 0) { count= Spotlist_count(*spotlist, 0); end_lba= 0; for(i= 0; i < count; i++) { Spotlist_get_item(*spotlist, i, &start_lba, &blocks, &quality, 0); if(start_lba + blocks > end_lba) end_lba= start_lba + blocks; } if(read_capacity > end_lba) { hret= Spotlist_add_item(*spotlist, end_lba, read_capacity - end_lba, Xorriso_read_quality_untesteD, 0); if(hret < ret) ret= hret; } } if(ret > 0) ret= Xorriso_update_in_sector_map(xorriso, *spotlist, read_chunk, job, 0); if(ret > 0) { ret= Xorriso_spotlist_to_sectormap(xorriso, *spotlist, read_chunk, &(job->sector_map), !!job->untested_valid); if(ret > 0 && job->sector_map_path[0]) { ret= Sectorbitmap_to_file(job->sector_map, job->sector_map_path, toc_info, xorriso->info_text, &os_errno, 0); if(ret <= 0) { if(xorriso->info_text[0]) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, os_errno, "FAILURE", 0); } } } if(toc_info != NULL) free(toc_info); if(ret <= 0) Spotlist_destroy(spotlist, 0); if(caps!=NULL) burn_disc_free_multi_caps(&caps); return(ret); } /* @param flag bit1= for Xorriso_check_interval(): no pacifier messages */ int Xorriso_read_file_data(struct XorrisO *xorriso, IsoNode *node, char *img_path, char *disk_path, off_t img_offset, off_t disk_offset, off_t bytes, int flag) { int ret, i, lba_count= 0, *start_lbas= NULL, *end_lbas= NULL, read_chunk= 16; int lba, count, blocks, quality, spot, bad_extract= 0; off_t size= 0, file_base_bytes= 0, file_processed_bytes= 0, img_adr; off_t new_file_base_bytes, upto_file_bytes, start_byte= 0; char sfe[5*SfileadrL]; struct SpotlisT *spotlist= NULL; struct CheckmediajoB *job= NULL; upto_file_bytes= img_offset + bytes; /* >>> make Xorriso_check_interval() ready for copying in byte granularity */ if(img_offset % (off_t) 2048) { sprintf(xorriso->info_text, "Image address offset is not a multiple of 2048"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } ret= Xorriso__start_end_lbas(node, &lba_count, &start_lbas, &end_lbas, &size, 0); if(ret <= 0) { Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "File object %s is currently not a data file from the loaded image", Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); goto ex; } if(img_offset + bytes < size && bytes > 0) size= img_offset + bytes; ret= Checkmediajob_new(&job, 0); if(ret <= 0) goto ex; if(xorriso->check_media_default != NULL) Checkmediajob_copy(xorriso->check_media_default, job, 0); job->min_lba= -1; job->max_lba= -1; job->sector_map_path[0]= 0; ret= Spotlist_new(&spotlist, 0); if(ret <= 0) {ret= -1; goto ex;} if(Sfile_str(job->data_to_path, disk_path, 0) <= 0) {ret= -1; goto ex;} Xorriso_open_job_data_to(xorriso, job, 0); if(ret <= 0) goto ex; for(i= 0; i < lba_count && file_base_bytes < upto_file_bytes; i++) { lba= start_lbas[i]; count= end_lbas[i] + 1 - start_lbas[i]; new_file_base_bytes= file_base_bytes + ((off_t) count) * (off_t) 2048; /* skip intervals before img_offset */ if(new_file_base_bytes <= img_offset) { file_base_bytes= new_file_base_bytes; continue; } /* Eventually adjust first interval start */ img_adr= ((off_t) lba) * (off_t) 2048; if(file_base_bytes < img_offset) { img_adr+= img_offset - file_base_bytes; lba= img_adr / (off_t) 2048; count= end_lbas[i] + 1 - lba; file_base_bytes= img_offset; } /* Eventually omit surplus blocks */ if(new_file_base_bytes > upto_file_bytes) count-= (new_file_base_bytes - upto_file_bytes) / (off_t) 2048; /* Adjust job */ job->data_to_offset= file_processed_bytes - img_adr + disk_offset; job->data_to_limit= size - file_base_bytes; file_processed_bytes+= ((off_t) count) * (off_t) 2048; ret= Xorriso_check_interval(xorriso, spotlist, job, lba, count, read_chunk, 0, (flag & 2)); if(ret <= 0) goto ex; if (ret == 2) { sprintf(xorriso->info_text, "Attempt aborted to extract data from %s", Text_shellsafe(img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } file_base_bytes= new_file_base_bytes; } /* Use spotlist to evaluate damage */ file_base_bytes= 0; count= Spotlist_count(spotlist, 0); for(spot= 0; spot < count; spot++) { ret= Spotlist_get_item(spotlist, spot, &lba, &blocks, &quality, 0); if(ret <= 0) continue; if(quality < Xorriso_read_quality_valiD) { for(i= 0; i < lba_count; i++) { if(start_lbas[i] <= lba && end_lbas[i] >= lba) { start_byte= (lba - start_lbas[i]) * (off_t) 2048 + file_base_bytes; break; } file_base_bytes+= ((off_t) (end_lbas[i] + 1 - start_lbas[i])) * (off_t) 2048; } if(i < lba_count) { sprintf(xorriso->info_text, "Bad extract : %14.f , %14.f , %s\n", (double) start_byte, ((double) blocks) * 2048.0, Text_shellsafe(disk_path, sfe, 0)); Xorriso_info(xorriso, 0); bad_extract= 1; } } } ret= !bad_extract; ex:; if(start_lbas != NULL) free((char *) start_lbas); if(end_lbas != NULL) free((char *) end_lbas); Spotlist_destroy(&spotlist, 0); Checkmediajob_destroy(&job, 0); return(ret); } int Xorriso_extract_cut(struct XorrisO *xorriso, char *img_path, char *disk_path, off_t img_offset, off_t bytes, int flag) { int ret, stbuf_ret, read_raw; double mem_lut= 0.0; char eff_img_path[SfileadrL], eff_disk_path[SfileadrL], sfe[SfileadrL*5]; IsoImage *volume; IsoNode *node; ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(ret); ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, img_path, eff_img_path, 0); if(ret<=0) return(ret); ret= Xorriso_node_from_path(xorriso, volume, eff_img_path, &node, 0); if(ret<=0) return(ret); ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, disk_path, eff_disk_path, 2 | 4); if(ret<=0) return(ret); Xorriso_pacifier_reset(xorriso, 0); mem_lut= xorriso->last_update_time; ret= Xorriso_handle_collision(xorriso, node, img_path, eff_disk_path, disk_path, &stbuf_ret, 0); if(ret<=0 || ret==3) return(0); /* If it is a non-filtered stream from the ISO image and img_offset is a multiple of 2048 then use Xorriso_read_file_data() for random access offset. */ if(!LIBISO_ISREG(node)) { Xorriso_msgs_submit(xorriso, 0, eff_disk_path, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-extract_cut: ISO file %s is not a data file", Text_shellsafe(eff_img_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } read_raw= 0; if((img_offset % 2048) == 0) { ret= Xorriso_is_plain_image_file(xorriso, node, "", 0); if(ret > 0) read_raw= 1; } if (read_raw) { ret= Xorriso_read_file_data(xorriso, node, eff_img_path, eff_disk_path, img_offset, (off_t) 0, bytes, 0); if(ret<=0) return(ret); } else { ret= Xorriso_tree_restore_node(xorriso, node, eff_img_path, img_offset, eff_disk_path, (off_t) 0, bytes, 2 | 8); if(ret<=0) return(ret); } ret= Xorriso_restore_properties(xorriso, eff_disk_path, node, 0); if(ret<=0) return(ret); if(mem_lut != xorriso->last_update_time) Xorriso_pacifier_callback(xorriso, "sectors examined", xorriso->pacifier_count, 0, "", 1); return(1); } int Xorriso_get_local_charset(struct XorrisO *xorriso, char **name, int flag) { (*name)= iso_get_local_charset(0); return(1); } int Xorriso_set_local_charset(struct XorrisO *xorriso, char *name, int flag) { int ret; char *nl_charset, sfe[5 * SfileadrL]; iconv_t iconv_ret= (iconv_t) -1; nl_charset= nl_langinfo(CODESET); if(name == NULL) name= nl_charset; if(name != NULL) { iconv_ret= iconv_open(nl_charset, name); if(iconv_ret == (iconv_t) -1) goto cannot; else iconv_close(iconv_ret); } ret= iso_set_local_charset(name, 0); if(ret <= 0) { cannot:; sprintf(xorriso->info_text, "-local_charset: Cannot assume as local character set: %s", Text_shellsafe(name, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(0); } sprintf(xorriso->info_text, "Local character set is now assumed as: %s", Text_shellsafe(name, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); return(1); } int Xorriso_relax_compliance(struct XorrisO *xorriso, char *mode, int flag) { char *npt, *cpt; int l, was; was= xorriso->relax_compliance; npt= cpt= mode; for(; npt!=NULL; cpt= npt+1) { npt= strchr(cpt,':'); if(npt==NULL) l= strlen(cpt); else l= npt-cpt; if(l == 0) continue; if((l == 6 && strncmp(cpt, "strict", l) == 0) || (l == 5 && strncmp(cpt, "clear", l) == 0)) { xorriso->relax_compliance= 0; } else if(l == 7 && strncmp(cpt, "default", l) == 0) { xorriso->relax_compliance= Xorriso_relax_compliance_defaulT; } else if((l == 12 && strncmp(cpt, "omit_version", l) == 0) || (l == 15 && strncmp(cpt, "omit_version_on", l) == 0) ) { xorriso->relax_compliance|= isoburn_igopt_omit_version_numbers; } else if((l == 16 && strncmp(cpt, "omit_version_off", l) == 0)) { xorriso->relax_compliance&= ~isoburn_igopt_omit_version_numbers; } else if((l == 16 && strncmp(cpt, "only_iso_version", l) == 0) || (l == 19 && strncmp(cpt, "only_iso_version_on", l) == 0) ) { xorriso->relax_compliance|= isoburn_igopt_only_iso_versions; } else if((l == 20 && strncmp(cpt, "only_iso_version_off", l) == 0)) { xorriso->relax_compliance&= ~isoburn_igopt_only_iso_versions; } else if((l == 10 && strncmp(cpt, "deep_paths", l) == 0) || (l == 13 && strncmp(cpt, "deep_paths_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_allow_deep_paths; } else if(l == 14 && strncmp(cpt, "deep_paths_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_allow_deep_paths; } else if((l == 10 && strncmp(cpt, "long_paths", l) == 0) || (l == 13 && strncmp(cpt, "long_paths_on", l) == 0) ) { xorriso->relax_compliance|= isoburn_igopt_allow_longer_paths; } else if(l == 14 && strncmp(cpt, "long_paths_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_allow_longer_paths; } else if((l == 10 && strncmp(cpt, "long_names", l) == 0) || (l == 13 && strncmp(cpt, "long_names_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_max_37_char_filenames; } else if(l == 14 && strncmp(cpt, "long_names_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_max_37_char_filenames; } else if((l == 13 && strncmp(cpt, "no_force_dots", l) == 0) || (l == 16 && strncmp(cpt, "no_force_dots_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_no_force_dots; } else if(l == 17 && strncmp(cpt, "no_force_dots_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_no_force_dots; } else if((l == 15 && strncmp(cpt, "no_j_force_dots", l) == 0) || (l == 18 && strncmp(cpt, "no_j_force_dots_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_no_j_force_dots; } else if(l == 19 && strncmp(cpt, "no_j_force_dots_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_no_j_force_dots; } else if((l == 9 && strncmp(cpt, "lowercase", l) == 0) || (l == 12 && strncmp(cpt, "lowercase_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_allow_lowercase; } else if(l == 13 && strncmp(cpt, "lowercase_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_allow_lowercase; } else if((l == 10 && strncmp(cpt, "full_ascii", l) == 0) || (l == 13 && strncmp(cpt, "full_ascii_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_allow_full_ascii; } else if(l == 14 && strncmp(cpt, "full_ascii_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_allow_full_ascii; } else if((l == 17 && strncmp(cpt, "joliet_long_paths", l) == 0) || (l == 20 && strncmp(cpt, "joliet_long_paths_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_joliet_longer_paths; } else if(l == 21 && strncmp(cpt, "joliet_long_paths_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_joliet_longer_paths; } else if((l == 10 && strncmp(cpt, "always_gmt", l) == 0) || (l == 13 && strncmp(cpt, "always_gmt_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_always_gmt; } else if(l == 14 && strncmp(cpt, "always_gmt_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_always_gmt; } else if((l == 9 && strncmp(cpt, "rec_mtime", l) == 0) || (l == 12 && strncmp(cpt, "rec_mtime_on", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_dir_rec_mtime; } else if(l == 13 && strncmp(cpt, "rec_mtime_off", l) == 0) { xorriso->relax_compliance&= ~isoburn_igopt_dir_rec_mtime; } else if((l == 6 && strncmp(cpt, "old_rr", l) == 0) || (l == 9 && strncmp(cpt, "old_rr_on", l) == 0) || (l == 10 && strncmp(cpt, "new_rr_off", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_rrip_version_1_10 | isoburn_igopt_aaip_susp_1_10; } else if((l == 10 && strncmp(cpt, "old_rr_off", l) == 0) || (l == 9 && strncmp(cpt, "new_rr_on", l) == 0) || (l == 6 && strncmp(cpt, "new_rr", l) == 0)) { xorriso->relax_compliance&= ~(isoburn_igopt_rrip_version_1_10 | isoburn_igopt_aaip_susp_1_10); } else if((l == 14 && strncmp(cpt, "aaip_susp_1_10", l) == 0) || (l == 17 && strncmp(cpt, "aaip_susp_1_10_on", l) == 0) || (l == 18 && strncmp(cpt, "aaip_susp_1_12_off", l) == 0)) { xorriso->relax_compliance|= isoburn_igopt_aaip_susp_1_10; } else if((l == 18 && strncmp(cpt, "aaip_susp_1_10_off", l) == 0) || (l == 17 && strncmp(cpt, "aaip_susp_1_12_on", l) == 0) || (l == 14 && strncmp(cpt, "aaip_susp_1_12", l) == 0)) { xorriso->relax_compliance&= ~isoburn_igopt_aaip_susp_1_10; } else if((l == 8 && strncmp(cpt, "iso_9660", l) == 0) || (l == 11 && strncmp(cpt, "iso_9660_on", l) == 0)) { /* may have a meaning in future */; } else if(l == 12 && strncmp(cpt, "iso_9660_off", l) == 0) { /* may have a meaning in future */; Xorriso_msgs_submit(xorriso, 0, "-compliance -iso_9660_off : Cannot do anything else but ISO 9660", 0, "FAILURE", 0); } else { if(linfo_text, "-compliance: unknown rule '%s'", cpt); else sprintf(xorriso->info_text, "-compliance: oversized rule parameter (%d)", l); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); xorriso->relax_compliance= was; return(0); } } return(1); } /* @return 1=ok 2=ok, is default setting */ int Xorriso_get_relax_text(struct XorrisO *xorriso, char mode[1024], int flag) { int r; r= xorriso->relax_compliance; if(r == 0) { strcpy(mode, "strict"); return(1); } strcpy(mode, "clear"); if(r & isoburn_igopt_omit_version_numbers) strcat(mode, ":omit_version"); if(r & isoburn_igopt_only_iso_versions) strcat(mode, ":only_iso_version"); if(r & isoburn_igopt_allow_deep_paths) strcat(mode, ":deep_paths"); if(r & isoburn_igopt_allow_longer_paths) strcat(mode, ":long_paths"); if(r & isoburn_igopt_max_37_char_filenames) strcat(mode, ":long_names"); if(r & isoburn_igopt_no_force_dots) strcat(mode, ":no_force_dots"); if(r & isoburn_igopt_no_j_force_dots) strcat(mode, ":no_j_force_dots"); if(r & isoburn_igopt_allow_lowercase) strcat(mode, ":lowercase"); if(r & isoburn_igopt_allow_full_ascii) strcat(mode, ":full_ascii"); if(r & isoburn_igopt_joliet_longer_paths) strcat(mode, ":joliet_long_paths"); if(r & isoburn_igopt_always_gmt) strcat(mode, ":always_gmt"); if(r & isoburn_igopt_dir_rec_mtime) strcat(mode, ":rec_mtime"); if(r & isoburn_igopt_rrip_version_1_10) { strcat(mode, ":old_rr"); if(!(r & isoburn_igopt_aaip_susp_1_10)) strcat(mode, ":aaip_susp_1_10_off"); } else { strcat(mode, ":new_rr"); if(r & isoburn_igopt_aaip_susp_1_10) strcat(mode, ":aaip_susp_1_10"); } return(1 + (r == Xorriso_relax_compliance_defaulT)); } /** @param flag bit0= print mount command to result channel rather than performing it bit1= do not allow prefixes with cmd bit2= interpret unprefixed cmd as shell: */ int Xorriso_mount(struct XorrisO *xorriso, char *dev, int adr_mode, char *adr_value, char *cmd, int flag) { int ret, lba, track, session, params_flag= 0, is_safe= 0, is_extra_drive= 0; int give_up= 0, mount_chardev= 0, status; char volid[33], *devadr, mount_command[SfileadrL], adr_data[163], *adr_pt; char *dev_path, libburn_adr[BURN_DRIVE_ADR_LEN + SfileadrL]; char sfe[5 * SfileadrL], *dpt, *sysname= ""; struct stat stbuf; struct burn_drive_info *dinfo= NULL; struct burn_drive *drive= NULL; devadr= dev; adr_pt= adr_value; if(strcmp(dev, "indev") == 0) { ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to perform -mount \"indev\"", 0); if(ret<=0) goto ex; dev_path= devadr= xorriso->indev; if(strncmp(dev_path, "stdio:", 6) == 0) dev_path+= 6; if(xorriso->in_drive_handle == xorriso->out_drive_handle) give_up= 3; else give_up= 1; } else if(strcmp(dev, "outdev") == 0) { ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to perform -mount \"outdev\"", 2); if(ret<=0) goto ex; dev_path= devadr= xorriso->outdev; if(strncmp(dev_path, "stdio:", 6) == 0) dev_path+= 6; if(xorriso->in_drive_handle == xorriso->out_drive_handle) give_up= 3; else give_up= 2; } else { is_extra_drive= 1; dev_path= dev; if(strncmp(dev_path, "stdio:", 6) == 0) dev_path+= 6; /* do only accept regular files and block devices */ ret= stat(dev_path, &stbuf); if(ret == -1) { sprintf(xorriso->info_text, "Cannot determine properties of file %s", Text_shellsafe(dev_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } ret= System_uname(&sysname, NULL, NULL, NULL, 0); if(ret > 0 && strcmp(sysname, "FreeBSD") == 0) mount_chardev= 1; if(!(S_ISREG(stbuf.st_mode) || (S_ISBLK(stbuf.st_mode) && !mount_chardev) || (S_ISCHR(stbuf.st_mode) && !mount_chardev))) { sprintf(xorriso->info_text, "File object is not suitable as mount device: %s", Text_shellsafe(dev_path, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } /* Aquire drive as direct libburn address or via stdio: prefix */ ret= burn_drive_convert_fs_adr(dev, libburn_adr); Xorriso_process_msg_queues(xorriso,0); if(ret < 0) {ret= -1; goto ex;} if(ret == 0 && strncmp(dev, "stdio:", 6) != 0) sprintf(libburn_adr, "stdio:%s", dev); burn_preset_device_open(xorriso->drives_exclusive, 0, 0); ret= isoburn_drive_aquire(&dinfo, libburn_adr, 1); burn_preset_device_open(1, 0, 0); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) {ret= 0; goto ex;} drive= dinfo[0].drive; } if(adr_mode == 4 && strlen(adr_pt) <= 80) { ret= Xorriso__bourne_to_reg(adr_pt, adr_data, 0); if(ret == 1) { params_flag|= 4; adr_pt= adr_data; } } ret= isoburn_get_mount_params(drive, adr_mode, adr_pt, &lba, &track, &session, volid, params_flag); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) goto ex; if(session <= 0 || track <= 0 || ret == 2) { Xorriso_msgs_submit(xorriso, 0, "-mount : Given address does not point to an ISO 9660 session", 0, "FAILURE", 0); ret= 0; goto ex; } if(strstr(devadr, "stdio:") == devadr) devadr+= 6; ret= Xorriso_make_mount_cmd(xorriso, cmd, lba, track, session, volid, devadr, mount_command, flag & (2 | 4)); if(ret <= 0) goto ex; if(ret == 2) is_safe= 1; if(is_extra_drive) { isoburn_drive_release(drive, 0); burn_drive_info_free(dinfo); drive= NULL; } else if(give_up > 0 && !((flag & 1) || (xorriso->mount_opts_flag & 1))) { Xorriso_give_up_drive(xorriso, give_up); if(ret <= 0) goto ex; } Xorriso_process_msg_queues(xorriso,0); sprintf(xorriso->info_text, "Volume id : %s\n", Text_shellsafe(volid, sfe, 0)); Xorriso_info(xorriso, 0); if(flag & 1) { sprintf(xorriso->result_line, "%s\n", mount_command); Xorriso_result(xorriso,0); } else { sprintf(xorriso->info_text, "Mount command: %s\n", mount_command); Xorriso_info(xorriso, 0); if(!is_safe) { Xorriso_msgs_submit(xorriso, 0, "-mount : Will not perform mount command which stems from command template.", 0, "SORRY", 0); sprintf(xorriso->result_line, "%s\n", mount_command); Xorriso_result(xorriso,0); } else { ret= Xorriso_execv(xorriso, mount_command, "/bin:/sbin", &status, 1); if(WIFEXITED(status) && WEXITSTATUS(status) != 0) { sprintf(xorriso->info_text, "-mount : mount command failed with exit value %d", (int) WEXITSTATUS(ret)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } sprintf(xorriso->info_text, "\nMounted session %d of device %s", session, Text_shellsafe(dev_path, sfe, 0)); dpt= strchr(cmd, ':'); if(dpt == NULL) dpt= cmd ; else dpt++; sprintf(xorriso->info_text + strlen(xorriso->info_text), " as directory %s\n", Text_shellsafe(dpt, sfe, 0)); Xorriso_info(xorriso, 0); } } ret= 1; ex:; if(is_extra_drive && drive != NULL) { isoburn_drive_release(drive, 0); burn_drive_info_free(dinfo); Xorriso_process_msg_queues(xorriso,0); } return(ret); } int Xorriso_auto_driveadr(struct XorrisO *xorriso, char *adr, char *result, int flag) { int ret, is_known_mmc= 0; char *path_pt, libburn_adr[BURN_DRIVE_ADR_LEN + SfileadrL]; char *abs_pt, abs_adr[SfileadrL]; path_pt= adr; if(strncmp(adr, "stdio:", 6) == 0) path_pt= adr + 6; else if(strncmp(adr, "mmc:", 4) == 0) path_pt= adr + 4; /* <<< replace by Xorriso_normalize_img_path() ? */; if(path_pt[0] != '/') { abs_pt= getcwd(abs_adr, SfileadrL - 1); if(abs_pt == NULL) { Xorriso_msgs_submit(xorriso, 0, "Relative drive path given. Cannot determine working directory.", errno, "FAILURE", 0); return(-1); } ret= Sfile_add_to_path(abs_adr, path_pt, 0); if(ret <= 0) return(-1); } is_known_mmc= burn_drive_convert_fs_adr(path_pt, libburn_adr); Xorriso_process_msg_queues(xorriso,0); ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_whitelist, path_pt, 0); if(ret > 0) goto ok; ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_blacklist, path_pt, 0); if(ret < 0) return(ret); if(ret) { strcpy(xorriso->info_text, "Drive address "); Text_shellsafe(adr, xorriso->info_text, 1); strcat(xorriso->info_text, " rejected because: -drive_class 'banned' "); Text_shellsafe(Xorriso_get_pattern(xorriso, xorriso->drive_blacklist, ret - 1, 0), xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } /* if in greylist and not MMC and not stdio prefix: reject */ if(is_known_mmc < 0) return(ret); if(adr == path_pt && !is_known_mmc) { /* no prefix, no MMC */ ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_greylist, path_pt,0); if(ret < 0) return(ret); if(ret) { strcpy(xorriso->info_text, "Drive address "); Text_shellsafe(adr, xorriso->info_text, 1); strcat(xorriso->info_text, " rejected because: not MMC and -drive_class 'risky' "); Text_shellsafe(Xorriso_get_pattern(xorriso,xorriso->drive_greylist, ret - 1, 0), xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); Xorriso_msgs_submit(xorriso, 0, "If the address is a legitimate target, prepend \"stdio:\"", 0, "HINT", 0); return(0); } } ok:; if(strncmp(adr, "mmc:", 4) == 0) { if(Sfile_str(result, path_pt, 0) <= 0) return(0); } else if(adr == path_pt && is_known_mmc <= 0) { Sfile_str(result, "stdio:", 0); if(Sfile_str(result, adr, 1) <= 0) return(0); } else { if(Sfile_str(result, adr, 0) <= 0) return(0); } if(strncmp(result, "stdio:", 6)==0) { if(xorriso->ban_stdio_write) { strcpy(xorriso->info_text, "Drive address banned by -ban_stdio_write : "); Text_shellsafe(result, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } } return(1); } /* @param flag bit0= do not remove leading slash bit1= append flatly to result_line and put out */ int Xorriso_getfname(struct XorrisO *xorriso, char *path, int flag) { int ret, path_offset= 0, bsl_mem; char *bsl_path= NULL; if(path[0] == '/' && !(flag & 1)) path_offset= 1; /* backslash escaped path rather than shellsafe path */ ret= Sfile_bsl_encoder(&bsl_path, path + path_offset, strlen(path + path_offset), 8); if(ret <= 0) return(-1); if(flag & 2) { sprintf(xorriso->result_line + strlen(xorriso->result_line), "%s\n", bsl_path[0] ? bsl_path : "."); } else { sprintf(xorriso->result_line, "# file: %s\n", bsl_path[0] ? bsl_path : "."); } free(bsl_path); bsl_path= NULL; /* temporarily disable -backslash_codes with result output */ bsl_mem= xorriso->bsl_interpretation; xorriso->bsl_interpretation= 0; Xorriso_result(xorriso, 0); xorriso->bsl_interpretation= bsl_mem; return(1); } /* @param node Opaque handle to IsoNode which is to be inquired instead of path if it is not NULL. @param path is used as address if node is NULL. @param acl_text if acl_text is not NULL, then *acl_text will be set to the ACL text (without comments) of the file object. In this case it finally has to be freed by the caller. @param flag bit0= do not report to result but only retrieve ACL text bit1= check for existence of true ACL (not fabricated), do not allocate and set acl_text but return 1 or 2 bit2-3: what ALC to retrieve: 0= "access" and "default", mark "default:" 1= "access" only 2= "default" only, do not mark "default:" bit4= get "access" ACL only if not trivial @return 2 ok, no ACL available, eventual *acl_text will be NULL 1 ok, ACL available, eventual *acl_text stems from malloc() <=0 error */ int Xorriso_getfacl(struct XorrisO *xorriso, void *in_node, char *path, char **acl_text, int flag) { int ret, d_ret, result_len= 0, pass, what; IsoNode *node; char *text= NULL, *d_text= NULL, *cpt, *npt; uid_t uid; gid_t gid; struct passwd *pwd; struct group *grp; what= (flag >> 2) & 3; if(acl_text != NULL) *acl_text= NULL; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) goto ex; } ret= iso_node_get_acl_text(node, &text, &d_text, flag & 16); d_ret= (d_text != NULL); if(ret < 0 || d_ret < 0) { if(path != NULL && path[0] != 0) { strcpy(xorriso->info_text, "Error with obtaining ACL of "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } ret= 0; goto ex; } if(flag & 2) { ret= 1 + (ret != 1 && d_ret == 0); goto ex; } if((ret == 0 || ret == 2) && d_ret == 0) { if(flag & 1) { ret= 1 + (ret == 0); goto ex; } strcpy(xorriso->info_text, "No ACL associated with "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); if(ret == 0) {ret= 2; goto ex;} } if(!(flag & 1)) { ret= Xorriso_getfname(xorriso, path, 0); if(ret <= 0) goto ex; uid= iso_node_get_uid(node); pwd= getpwuid(uid); if(pwd == NULL) sprintf(xorriso->result_line, "# owner: %.f\n", (double) uid); else sprintf(xorriso->result_line, "# owner: %s\n", pwd->pw_name); Xorriso_result(xorriso, 0); gid= iso_node_get_gid(node); grp= getgrgid(gid); if(grp == NULL) sprintf(xorriso->result_line, "# group: %.f\n", (double) gid); else sprintf(xorriso->result_line, "# group: %s\n", grp->gr_name); Xorriso_result(xorriso, 0); } for(pass= 0; pass < 1 + (acl_text != NULL && !(flag & 2)); pass++) { if(pass) { *acl_text= calloc(result_len + 1, 1); if(*acl_text == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } } if(text != NULL && what <= 1) { for(npt= cpt= text; npt != NULL; cpt= npt + 1) { npt= strchr(cpt, '\n'); if(npt != NULL) *npt= 0; if(*cpt == 0) { if(d_text != NULL || pass) { if(npt != NULL) *npt= '\n'; continue; } } else result_len+= strlen(cpt) + 1; if(pass) { sprintf(*acl_text + strlen(*acl_text), "%s\n", cpt); } else if(!(flag & 1)) { Sfile_str(xorriso->result_line, cpt, 0); strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); } if(npt != NULL) *npt= '\n'; } } if(d_text != NULL && (what == 0 || what == 2)) { for(npt= cpt= d_text; npt != NULL; cpt= npt + 1) { npt= strchr(cpt, '\n'); if(npt != NULL) *npt= 0; if(*cpt != 0) { if(pass) { if(what == 0) sprintf(*acl_text + strlen(*acl_text), "default:%s\n", cpt); else sprintf(*acl_text + strlen(*acl_text), "%s\n", cpt); } else { xorriso->result_line[0]= 0; if(what == 0) Sfile_str(xorriso->result_line, "default:", 0); Sfile_str(xorriso->result_line, cpt, 1); result_len+= strlen(cpt) + 9; } } else xorriso->result_line[0]= 0; if(pass== 0 && !(flag & 1)) { strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); } if(npt != NULL) *npt= '\n'; } } } ret= 1; ex:; iso_node_get_acl_text(node, &text, &d_text, 1 << 15); return(ret); } int Xorriso_set_ignore_aclea(struct XorrisO *xorriso, int flag) { int ret, hflag; IsoImage *volume; ret= Xorriso_get_volume(xorriso, &volume, 1); if(ret<=0) return(ret); hflag= (~xorriso->do_aaip) & 1; if((xorriso->ino_behavior & (1 | 2)) && !(xorriso->do_aaip & (4 | 16))) hflag|= 2; iso_image_set_ignore_aclea(volume, hflag); return(1); } /* @param node Opaque handle to IsoNode which is to be manipulated instead of path if it is not NULL. @param path is used as address if node is NULL. @param access_text "access" ACL in long text form @param default_text "default" ACL in long text form @param flag bit0= do not warn of root directory if not capable of AAIP @return >0 success , <=0 failure */ int Xorriso_setfacl(struct XorrisO *xorriso, void *in_node, char *path, char *access_text, char *default_text, int flag) { int ret; IsoNode *node; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) goto ex; } ret= iso_node_set_acl_text(node, access_text, default_text, 0); if(ret <= 0) { if(path != NULL && path[0] != 0) { strcpy(xorriso->info_text, "Error with setting ACL of "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } ret= 0; goto ex; } Xorriso_set_change_pending(xorriso, 0); ret= 1; ex:; Xorriso_process_msg_queues(xorriso,0); return(ret); } /* @param flag bit0= do not report to result but only retrieve attr text bit1= path is disk_path bit3= do not ignore eventual non-user attributes. bit5= in case of symbolic link on disk: inquire link target bit6= check for existence of xattr, return 0 or 1 (depends also on bit3) */ int Xorriso_getfattr(struct XorrisO *xorriso, void *in_node, char *path, char **attr_text, int flag) { int ret= 1, i, bsl_mem, result_len= 0, pass; size_t num_attrs= 0, *value_lengths= NULL; char **names= NULL, **values= NULL, *bsl; if(attr_text != NULL) *attr_text= NULL; ret= Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names, &value_lengths, &values, flag & (2 | 8 | 32)); if(ret <= 0) goto ex; if(flag & 64) { ret= (num_attrs > 0); goto ex; } if(num_attrs == 0) {ret= 2; goto ex;} if(!(flag & 1)) { ret= Xorriso_getfname(xorriso, path, 0); if(ret <= 0) goto ex; } for(pass= 0; pass < 1 + (attr_text != NULL); pass++) { if(pass) { *attr_text= calloc(result_len + 1, 1); if(*attr_text == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } } for(i= 0; i < num_attrs; i++) { if(strlen(names[i]) + value_lengths[i] >= SfileadrL) { sprintf(xorriso->result_line, "# oversized: name %d , value %d bytes\n", (int) strlen(names[i]), (int) value_lengths[i]); } else { ret= Sfile_bsl_encoder(&bsl, names[i], strlen(names[i]), 8); if(ret <= 0) {ret= -1; goto ex;} strcpy(xorriso->result_line, bsl); free(bsl); ret= Sfile_bsl_encoder(&bsl, values[i], value_lengths[i], 8); if(ret <= 0) {ret= -1; goto ex;} sprintf(xorriso->result_line + strlen(xorriso->result_line), "=\"%s\"\n", bsl); free(bsl); } /* temporarily disable -backslash_codes with result output */ result_len+= strlen(xorriso->result_line); if(pass) { strcat(*attr_text, xorriso->result_line); } else if(!(flag & 1)) { bsl_mem= xorriso->bsl_interpretation; xorriso->bsl_interpretation= 0; Xorriso_result(xorriso, 0); xorriso->bsl_interpretation= bsl_mem; } } } if(!(flag & 1)) { strcpy(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); } ret= 1; ex:; Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names, &value_lengths, &values, 1 << 15); return(ret); } /* @param in_node Opaque handle to IsoNode which is to be manipulated instead of path if it is not NULL. @param path is used as address if node is NULL. @param num_attrs Number of attributes @param names Array of pointers to 0 terminated name strings @param value_lengths Array of byte lengths for each attribute payload @param values Array of pointers to the attribute payload bytes @param flag bit0= Do not maintain eventual existing ACL of the node bit1= Do not clear the existing attribute list bit2= Delete the attributes with the given names bit3= Allow non-user attributes. bit4= do not warn of root if incapable of AAIP @return >0 success , <=0 failure */ int Xorriso_setfattr(struct XorrisO *xorriso, void *in_node, char *path, size_t num_attrs, char **names, size_t *value_lengths, char **values, int flag) { int ret; IsoNode *node; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) goto ex; } ret= iso_node_set_attrs(node, num_attrs, names, value_lengths, values, flag & (1 | 2 | 4 | 8)); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when setting ACL and xattr to image node", 0, "FAILURE", 1); if(path != NULL && path[0] != 0) { strcpy(xorriso->info_text, "Error with setting xattr of "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } ret= 0; goto ex; } Xorriso_set_change_pending(xorriso, 0); ret= 1; ex:; Xorriso_process_msg_queues(xorriso,0); return(ret); } /* @param flag Bitfield for control purposes bit0= get default ACL rather than access ACL bit4= set *text = NULL and return 2 if the ACL matches st_mode permissions. bit5= in case of symbolic link: inquire link target bit15= free text and return 1 @return 1 ok 2 ok, trivial ACL found while bit4 is set, *text is NULL 0 no ACL manipulation adapter available / ACL not supported by fs -1 failure of system ACL service (see errno) -2 attempt to inquire ACL of a symbolic link without bit4 or bit5 resp. with no suitable link target */ int Xorriso_local_getfacl(struct XorrisO *xorriso, char *disk_path, char **text, int flag) { int ret, skip= 0, colons= 0, countdown= 0; char *acl= NULL, *cpt, *wpt; if(flag & (1 << 15)) { if(*text != NULL) free(*text); *text= NULL; return(1); } *text= NULL; ret= iso_local_get_acl_text(disk_path, &acl, flag & (1 | 16 | 32)); Xorriso_process_msg_queues(xorriso,0); if(ret < 0 || ret == 2) return(ret); if(acl == NULL) return(0); *text= strdup(acl); iso_local_get_acl_text(disk_path, &acl, 1 << 15); if(*text == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } /* Garbage collection about trailing remarks after 3 permission chars */ wpt= *text; for(cpt= *text; *cpt; cpt++) { if(skip) { if(*cpt == '\n') skip= 0; else continue; } if(*cpt == ':' && !countdown) { colons++; if(colons == 2) { countdown= 4; colons= 0; } } if(countdown > 0) { countdown--; if(countdown == 0) skip= 1; } *wpt= *cpt; wpt++; } *wpt= 0; return(1); } /* @param flag bit1= path is disk_path bit3= do not ignore eventual non-user attributes. bit5= in case of symbolic link on disk: inquire link target bit15= free memory */ int Xorriso_get_attrs(struct XorrisO *xorriso, void *in_node, char *path, size_t *num_attrs, char ***names, size_t **value_lengths, char ***values, int flag) { int ret, i, widx; IsoNode *node; if(flag & (1 << 15)) { if(flag & 2) { iso_local_get_attrs(NULL, num_attrs, names, value_lengths, values, 1 << 15); } else { iso_node_get_attrs(NULL, num_attrs, names, value_lengths, values, 1 << 15); } return(1); } *num_attrs= 0; if(flag & 2) { ret= iso_local_get_attrs(path, num_attrs, names, value_lengths, values, flag & (8 | 32)); if(ret < 0) { strcpy(xorriso->info_text, "Error with reading xattr of disk file "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); } } else { node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) goto ex; } ret= iso_node_get_attrs(node, num_attrs, names, value_lengths, values, 0); if(ret < 0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when obtaining xattr of ISO node", 0, "FAILURE", 1); goto ex; } if(!(flag & 8)) { /* Filter away any non-userspace xattr */; widx= 0; for(i= 0; i < *num_attrs; i++) { if(strncmp((*names)[i], "user.", 5) != 0) { free((*names)[i]); (*names)[i]= NULL; if((*values)[i] != NULL) { free((*values)[i]); (*values)[i]= NULL; } } else { if(widx != i) { (*names)[widx]= (*names)[i]; (*value_lengths)[widx]= (*value_lengths)[i]; (*values)[widx]= (*values)[i]; (*names)[i]= NULL; (*value_lengths)[i]= 0; (*values)[i]= NULL; } widx++; } } *num_attrs= widx; } } ret= 1; ex:; Xorriso_process_msg_queues(xorriso,0); return(ret); } int Xorriso_get_attr_value(struct XorrisO *xorriso, void *in_node, char *path, char *name, size_t *value_length, char **value, int flag) { int ret; size_t num_attrs= 0, *value_lengths= NULL, i; char **names = NULL, **values= NULL; *value= NULL; *value_length= 0; ret= Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names, &value_lengths, &values, 8); if(ret <= 0) goto ex; for(i= 0; i < num_attrs; i++) { if(strcmp(name, names[i]) != 0) continue; *value= calloc(value_lengths[i] + 1, 1); if(*value == NULL) {ret= -1; goto ex;} memcpy(*value, values[i], value_lengths[i]); (*value)[value_lengths[i]]= 0; *value_length= value_lengths[i]; ret= 1; goto ex; } ret= 0; ex: Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names, &value_lengths, &values, 1 << 15); return(ret); } /* @param flag bit0= use parameters dev,ino rather than disk_path bit1= compare attribute rather than setting it return: 0=dev,ino match, 1=mismatch, 2=no node attribute -1=error bit5= if not bit0: transfer dev,inode from eventual link target bit7= omit dev check mit bit1 */ int Xorriso_record_dev_inode(struct XorrisO *xorriso, char *disk_path, dev_t dev, ino_t ino, void *in_node, char *iso_path, int flag) { size_t l, di_l= 0; int i, ret; dev_t hdev; ino_t hino; char buf[66], *bufpt, *wpt, *di= NULL; static char *name= "isofs.di"; struct stat stbuf; if(!(flag & 1)) { if(flag & 32) { if(stat(disk_path, &stbuf) == -1) return(-1); } else { if(lstat(disk_path, &stbuf) == -1) return(-1); } dev= stbuf.st_dev; ino= stbuf.st_ino; } wpt= buf; hdev= dev; for(i= 0; hdev != 0; i++) hdev= hdev >> 8; l= i; *(wpt++)= l; for(i= 0; i < l; i++) *(wpt++)= dev >> (8 * (l - i - 1)); hino= ino; for(i= 0; hino != 0; i++) hino= hino >> 8; l= i; *(wpt++)= l; for(i= 0; i < l; i++) *(wpt++)= ino >> (8 * (l - i - 1)); l= wpt - buf; bufpt= buf; if(flag & 2) { /* Compare node attribute with bufpt,l */ ret= Xorriso_get_attr_value(xorriso, in_node, iso_path, "isofs.di", &di_l, &di, 0); if(ret < 0) goto ex; if(ret == 0) {ret= 2; goto ex;} if(flag & 128) { if(di_l <= 0) {ret= 1; goto ex;} hino= 0; for(i= di[0] + 2; i < di_l && i - di[0] - 2 < di[(int) di[0] + 1]; i++) hino= (hino << 8) | ((unsigned char *) di)[i]; if(hino != ino) {ret= 1; goto ex;} } else { if(l != di_l) {ret= 1; goto ex;} for(i= 0; i < l; i++) if(di[i] != buf[i]) {ret= 1; goto ex;} } ret= 0; } else { ret= Xorriso_setfattr(xorriso, in_node, iso_path, (size_t) 1, &name, &l, &bufpt, 2 | 8); } ex:; if(di != NULL) free(di); return(ret); } struct Xorriso_extF { int flag; /* unused yet */ IsoExternalFilterCommand *cmd; }; int Xorriso_extf_destroy(struct XorrisO *xorriso, struct Xorriso_extF **filter, int flag); /* @param flag see struct Xorriso_extF.flag */ int Xorriso_extf_new(struct XorrisO *xorriso, struct Xorriso_extF **filter, char *path, int argc, char **argv, int behavior, char *suffix, char *name, int flag) { int i; struct Xorriso_extF *o= NULL; IsoExternalFilterCommand *cmd; *filter= o= calloc(sizeof(struct Xorriso_extF), 1); if(o == NULL) goto failure; o->flag= flag; o->cmd= NULL; o->cmd= cmd= calloc(sizeof(IsoExternalFilterCommand), 1); if(cmd == NULL) goto failure; cmd->version= 0; cmd->refcount= 0; cmd->name= NULL; cmd->path= NULL; cmd->argv= NULL; cmd->argc= argc + 1; cmd->behavior= behavior; cmd->suffix= NULL; cmd->suffix= strdup(suffix); if(cmd->suffix == NULL) goto failure; cmd->path= strdup(path); if(cmd->path == NULL) goto failure; cmd->argv= calloc(sizeof(char *), argc + 2); if(cmd->argv == NULL) goto failure; for(i= 0; i < argc + 2; i++) cmd->argv[i]= NULL; cmd->argv[0]= strdup(path); if(cmd->argv[0] == NULL) goto failure; for(i= 0; i < argc; i++) { cmd->argv[i + 1]= strdup(argv[i]); if(cmd->argv[i] == NULL) goto failure; } cmd->name= strdup(name); if(cmd->name == NULL) goto failure; return(1); failure:; Xorriso_extf_destroy(xorriso, filter, 0); return(-1); } int Xorriso_extf_destroy(struct XorrisO *xorriso, struct Xorriso_extF **filter, int flag) { int i; IsoExternalFilterCommand *cmd; if(*filter == NULL) return(0); cmd= (*filter)->cmd; if(cmd != NULL) { if(cmd->refcount > 0) return(0); if(cmd->suffix != NULL) free(cmd->suffix); if(cmd->argv != NULL) { for(i= 0; i < cmd->argc; i++) if(cmd->argv[i] != NULL) free(cmd->argv[i]); free((char *) cmd->argv); } if(cmd->name != NULL) free(cmd->name); } free((char *) *filter); *filter= NULL; return(1); } int Xorriso_lookup_extf(struct XorrisO *xorriso, char *name, struct Xorriso_lsT **found_lst, int flag) { struct Xorriso_extF *filter; struct Xorriso_lsT *lst; for(lst= xorriso->filters; lst != NULL; lst= Xorriso_lst_get_next(lst, 0)) { filter= (struct Xorriso_extF *) Xorriso_lst_get_text(lst, 0); if(strcmp(filter->cmd->name, name) == 0) { *found_lst= lst; return(1); } } return(0); } int Xorriso_destroy_all_extf(struct XorrisO *xorriso, int flag) { struct Xorriso_extF *filter; struct Xorriso_lsT *lst, *next_lst; for(lst= xorriso->filters; lst != NULL; lst= next_lst) { filter= (struct Xorriso_extF *) Xorriso_lst_get_text(lst, 0); Xorriso_lst_detach_text(lst, 0); next_lst= Xorriso_lst_get_next(lst, 0); Xorriso_lst_destroy(&lst, 0); Xorriso_extf_destroy(xorriso, &filter, 0); } xorriso->filters= NULL; return(1); } /* @param flag bit0= return 2 if renaming is not possible by libisofs (always: if demanded strip suffix is missing or if suffix makes name length > 255) bit1= strip suffix rather than appending it */ int Xorriso_rename_suffix(struct XorrisO *xorriso, IsoNode *node, char *suffix, char *show_path, char new_name[], int flag) { int ret, lo= 0, ls= 0, strip_suffix; char *old_name= NULL, *show_name; strip_suffix= !!(flag & 2); old_name= strdup((char *) iso_node_get_name(node)); show_name= old_name; if(show_path != NULL) if(show_path[0] != 0) show_name= show_path; lo= strlen(old_name); ls= strlen(suffix); if(strip_suffix) { if(lo <= ls) { /* refuse gracefully */ ret= 2; goto ex; } if(strcmp(old_name + lo - ls, suffix) != 0) { ret= 2; goto ex; } if(lo >= SfileadrL) goto cannot_remove_suffix; strcpy(new_name, old_name); new_name[lo - ls]= 0; ret = iso_node_set_name(node, new_name); if (ret < 0) { Xorriso_process_msg_queues(xorriso,0); if (!(flag & 1)) Xorriso_report_iso_error(xorriso, "", ret, "Error when renaming ISO node", 0, "FAILURE", 1); cannot_remove_suffix:; strcpy(xorriso->info_text, "-set_filter: Cannot remove suffix from "); Text_shellsafe(show_name, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, (flag & 1) ? "WARNING" : "FAILURE", 0); ret= 2 * (flag & 1); goto ex; } } else { /* check whether suffix already present */ if(lo >= ls) if(strcmp(old_name + lo - ls, suffix) == 0) { /* refuse gracefully */ ret= 2; goto ex; } if(lo + ls > 255) { cannot_append_suffix:; strcpy(xorriso->info_text, "-set_filter: Cannot append suffix to "); Text_shellsafe(show_name, xorriso->info_text, 1); strcat(xorriso->info_text, ". Left unfiltered."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, (flag & 1) ? "WARNING" : "FAILURE", 0); ret= 2 * (flag & 1); goto ex; } sprintf(new_name, "%s%s", old_name, suffix); ret = iso_node_set_name(node, new_name); if (ret < 0) { Xorriso_process_msg_queues(xorriso,0); if (!(flag & 1)) Xorriso_report_iso_error(xorriso, "", ret, "Error when renaming ISO node", 0, "FAILURE", 1); goto cannot_append_suffix; } } ret= 1; ex:; if(old_name != NULL) free(old_name); Xorriso_process_msg_queues(xorriso,0); return(ret); } /* @param flag bit0= return 2 if renaming is not possible bit1= print pacifier messages */ int Xorriso_set_filter(struct XorrisO *xorriso, void *in_node, char *path, char *filter_name, int flag) { int ret, strip_suffix= 0, strip_filter= 0, filter_ret= 0; int explicit_suffix= 0, internal_filter= 0; IsoNode *node; IsoFile *file; struct Xorriso_lsT *found_lst; struct Xorriso_extF *found_filter; IsoExternalFilterCommand *cmd = NULL; char *old_name= NULL, new_name[SfileadrL], *suffix= ""; IsoStream *stream; int is_renamed= 0; new_name[0]= 0; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret <= 0) goto ex; } if(!LIBISO_ISREG(node)) { strcpy(xorriso->info_text, "-set_filter: Not a regular data file node "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0); ret= 0; goto ex; } file= (IsoFile *) node; if(strncmp(filter_name, "--remove-all-filters", 20) == 0) { strip_filter= 1; strip_suffix= 1; if(strlen(filter_name) > 21) { strip_suffix= (filter_name[20] != '+'); suffix= filter_name + 21; explicit_suffix= 1; } } else if(strcmp(filter_name, "--zisofs") == 0) { internal_filter= 1; } else if(strcmp(filter_name, "--zisofs-decode") == 0) { internal_filter= 2; } else if(strcmp(filter_name, "--gzip") == 0) { internal_filter= 3; suffix= ".gz"; strip_suffix= 0; explicit_suffix= 1; } else if(strcmp(filter_name, "--gunzip") == 0 || strcmp(filter_name, "--gzip-decode") == 0) { internal_filter= 4; suffix= ".gz"; strip_suffix= 1; explicit_suffix= 1; } else { ret= Xorriso_lookup_extf(xorriso, filter_name, &found_lst, 0); if(ret < 0) goto ex; if(ret == 0) { strcpy(xorriso->info_text, "-set_filter: Not a registered filter name "); Text_shellsafe(filter_name, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } found_filter= (struct Xorriso_extF *) Xorriso_lst_get_text(found_lst, 0); cmd= found_filter->cmd; suffix= cmd->suffix; strip_suffix= cmd->behavior & 8; } if(suffix[0]) { /* >>> would need full iso_rr_path of node for showing */; old_name= strdup((char *) iso_node_get_name(node)); ret= Xorriso_rename_suffix(xorriso, node, suffix, path, new_name, (flag & 1) | (strip_suffix ? 2 : 0)); if(ret <= 0 || ret == 2) goto ex; is_renamed= 1; } if(strip_filter) { while(1) { if(!explicit_suffix) { stream= iso_file_get_stream(file); if(strncmp(stream->class->type, "gzip", 4) == 0) { suffix= ".gz"; strip_suffix= 1; } else if(strncmp(stream->class->type, "pizg", 4) == 0) { suffix= ".gz"; strip_suffix= 0; } else { ret= iso_stream_get_external_filter(stream, &cmd, 0); if(ret > 0) { suffix= cmd->suffix; strip_suffix= !(cmd->behavior & 8); } } if(suffix[0]) { /* >>> would need the current renaming state of path */; ret= Xorriso_rename_suffix(xorriso, node, suffix, NULL, new_name, (flag & 1) | (strip_suffix << 1)); if(ret <= 0 || ret == 2) goto ex; } } ret= iso_file_remove_filter(file, 0); if(ret != 1) break; } filter_ret= 1; } else if (internal_filter == 1 || internal_filter == 2) { filter_ret = iso_file_add_zisofs_filter(file, 1 | (internal_filter & 2)); if(filter_ret < 0) { Xorriso_process_msg_queues(xorriso,0); if(!(internal_filter == 2 && filter_ret == ISO_ZISOFS_WRONG_INPUT)) Xorriso_report_iso_error(xorriso, "", filter_ret, "Error when setting filter to ISO node", 0, "FAILURE", 1); } } else if (internal_filter == 3 || internal_filter == 4) { filter_ret = iso_file_add_gzip_filter(file, 1 | ((internal_filter == 4) << 1)); if(filter_ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", filter_ret, "Error when setting filter to ISO node", 0, "FAILURE", 1); } } else { #ifndef Xorriso_allow_extf_suiD /* This is a final safety precaution before iso_file_add_external_filter() performs fork() and executes the alleged filter program. */ if(getuid() != geteuid()) { sprintf(xorriso->info_text, "-set_filter: UID and EUID differ. Will not run external programs."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); return(0); } #endif /* ! Xorriso_allow_extf_suiD */ filter_ret = iso_file_add_external_filter(file, cmd, 0); if(filter_ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", filter_ret, "Error when setting filter to ISO node", 0, "FAILURE", 1); } } if(filter_ret != 1 && new_name[0] && old_name != NULL) { ret = iso_node_set_name(node, old_name); if (ret < 0) { Xorriso_process_msg_queues(xorriso,0); if (!(flag & 1)) Xorriso_report_iso_error(xorriso, "", ret, "Error when renaming ISO node", 0, "FAILURE", 1); } } if(flag & 2) { xorriso->pacifier_count++; Xorriso_pacifier_callback(xorriso, "file filters processed", xorriso->pacifier_count, xorriso->pacifier_total, "", 0); } if(filter_ret < 0) { ret= 0; goto ex; } ret= filter_ret; ex:; if(old_name != NULL) free(old_name); Xorriso_process_msg_queues(xorriso,0); return(ret); } /* @param flag bit0= delete filter with the given name */ int Xorriso_external_filter(struct XorrisO *xorriso, char *name, char *options, char *path, int argc, char **argv, int flag) { int ret, delete= 0, behavior= 0, extf_flag= 0, is_banned= 0; char *what, *what_next, *suffix= ""; struct Xorriso_lsT *lst; struct Xorriso_extF *found_filter, *new_filter= NULL; #ifndef Xorriso_allow_external_filterS /* To be controlled by: configure --enable-external-filters */ sprintf(xorriso->info_text, "%s : Banned at compile time.", flag & 1 ? "-unregister_filter" : "-external_filter"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); sprintf(xorriso->info_text, "This may be changed at compile time by ./configure option --enable-external-filters"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0); is_banned= 1; #endif /* ! Xorriso_allow_external_filterS */ #ifndef Xorriso_allow_extf_suiD /* To be controlled by: configure --enable-external-filters-setuid */ if(getuid() != geteuid()) { sprintf(xorriso->info_text, "-set_filter: UID and EUID differ. Will not run external programs."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); sprintf(xorriso->info_text, "This may be changed at compile time by ./configure option --enable-external-filters-setuid"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0); is_banned= 1; } #endif /* ! Xorriso_allow_extf_suiD */ if(is_banned) return(0); if(xorriso->filter_list_closed) { sprintf(xorriso->info_text, "%s : Banned by previous command -close_filter_list", flag & 1 ? "-unregister_filter" : "-external_filter"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } if((!(flag & 1)) && path[0] != '/') { sprintf(xorriso->info_text, "-external_filter : Given command path does not begin by '/' : "); Text_shellsafe(path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } delete= flag & 1; ret= Xorriso_lookup_extf(xorriso, name, &lst, 0); if(ret < 0) return(ret); if(ret > 0) { if(delete) { found_filter= (struct Xorriso_extF *) Xorriso_lst_get_text(lst, 0); if(found_filter->cmd->refcount > 0) { sprintf(xorriso->info_text, "-external_filter: Cannot remove filter because it is in use by %.f nodes : ", (double) found_filter->cmd->refcount); Text_shellsafe(name, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } Xorriso_lst_detach_text(lst, 0); if(xorriso->filters == lst) xorriso->filters= Xorriso_lst_get_next(lst, 0); Xorriso_lst_destroy(&lst, 0); Xorriso_extf_destroy(xorriso, &found_filter, 0); ret= 1; goto ex; } strcpy(xorriso->info_text, "-external_filter: filter with given name already existing: "); Text_shellsafe(name, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } if(delete) { strcpy(xorriso->info_text, "-external_filter: filter with given name does not exist: "); Text_shellsafe(name, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } for(what= options; what!=NULL; what= what_next) { what_next= strchr(what, ':'); if(what_next!=NULL) { *what_next= 0; what_next++; } if(strncmp(what, "default", 7) == 0) { suffix= ""; behavior= 0; } else if(strncmp(what, "suffix=", 7) == 0) { suffix= what + 7; } else if(strcmp(what, "remove_suffix") == 0) { behavior|= 8; } else if(strcmp(what, "if_nonempty") == 0) { behavior|= 1; } else if(strcmp(what, "if_reduction") == 0) { behavior|= 2; } else if(strcmp(what, "if_block_reduction") == 0) { behavior|= 4; } else if(strncmp(what, "used=", 5) == 0) { ; /* this is informational output from -status */ } else if(what[0]) { strcpy(xorriso->info_text, "-external_filter: unknown option "); Text_shellsafe(what, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } } ret= Xorriso_extf_new(xorriso, &new_filter, path, argc, argv, behavior, suffix, name, extf_flag); if(ret <= 0) { could_not_create:; strcpy(xorriso->info_text, "-external_filter: Could not create filter object"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); goto ex; } ret= Xorriso_lst_append_binary(&(xorriso->filters), (char *) new_filter,0, 4); if(ret <= 0) goto could_not_create; ret= 1; ex:; if(ret <= 0) { if(new_filter != NULL) Xorriso_extf_destroy(xorriso, &new_filter, 0); } return(ret); } int Xorriso_status_extf(struct XorrisO *xorriso, char *filter, FILE *fp, int flag) /* bit1= do only report to fp */ { int i, maxl= 4 * SfileadrL; struct Xorriso_extF *extf; struct Xorriso_lsT *lst; char *line; line= xorriso->result_line; for(lst= xorriso->filters; lst != NULL; lst= Xorriso_lst_get_next(lst, 0)) { extf= (struct Xorriso_extF *) Xorriso_lst_get_text(lst, 0); strcpy(xorriso->result_line, "-external_filter "); Text_shellsafe(extf->cmd->name, line, 1); if(strlen(line) > maxl) continue; strcat(line, " "); if(extf->cmd->suffix[0]) { strcat(line, "suffix="); Text_shellsafe(extf->cmd->suffix, line, 1); if(strlen(line) > maxl) continue; strcat(line, ":"); } if(extf->cmd->behavior & 8) strcat(line, "remove_suffix:"); if(extf->cmd->behavior & 1) strcat(line, "if_nonempty:"); if(extf->cmd->behavior & 2) strcat(line, "if_reduction:"); if(extf->cmd->behavior & 4) strcat(line, "if_block_reduction:"); sprintf(line + strlen(line), "used=%.f ", (double) extf->cmd->refcount); if(strlen(line) > maxl) continue; Text_shellsafe(extf->cmd->path, line, 1); if(strlen(line) > maxl) continue; for(i= 1; i < extf->cmd->argc; i++) { strcat(line, " "); Text_shellsafe(extf->cmd->argv[i], line, 1); if(strlen(line) > maxl) break; } if(i < extf->cmd->argc) continue; strcat(line, " --\n"); Xorriso_status_result(xorriso, filter, fp, flag&2); } if(xorriso->filter_list_closed) { strcpy(line, "-close_filter_list\n"); Xorriso_status_result(xorriso, filter, fp, flag&2); } return(1); } int Xorriso_stream_type(struct XorrisO *xorriso, IsoNode *node, IsoStream *stream, char type_text[], int flag) { int ret, lba; char text[5]; strncpy(text, stream->class->type, 4); text[4]= 0; if(strcmp(text, "fsrc") == 0) { ret= Xorriso__file_start_lba(node, &lba, 0); if(ret > 0 && lba > 0) strcpy(type_text, "image"); else strcpy(type_text, "disk"); } else if(strcmp(text, "ziso") == 0) { strcpy(type_text, "--zisofs"); } else if(strcmp(text, "osiz") == 0) { strcpy(type_text, "--zisofs-decode"); } else if(strcmp(text, "gzip") == 0) { strcpy(type_text, "--gzip"); } else if(strcmp(text, "pizg") == 0) { strcpy(type_text, "--gunzip"); } else if(strcmp(text, "cout") == 0 || strcmp(text, "boot") == 0 || strcmp(text, "user") == 0 || strcmp(text, "extf") == 0) { strcpy(type_text, text); } else { Text_shellsafe(text, type_text, 0); } return(1); } int Xorriso_show_stream(struct XorrisO *xorriso, void *in_node, char *path, int flag) { int ret; IsoNode *node; IsoFile *file; IsoStream *stream= NULL, *input_stream; IsoExternalFilterCommand *cmd; char type_text[16], *source_path= NULL; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret <= 0) goto ex; } if(!LIBISO_ISREG(node)) {ret= 2; goto ex;} file= (IsoFile *) node; input_stream= iso_file_get_stream(file); Text_shellsafe(path, xorriso->result_line, 0); while(1) { stream= input_stream; input_stream= iso_stream_get_input_stream(stream, 0); if(input_stream == NULL) break; strcat(xorriso->result_line, " < "); Xorriso_stream_type(xorriso, node, stream, type_text, 0); strcat(xorriso->result_line, type_text); ret= iso_stream_get_external_filter(stream, &cmd, 0); if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); Xorriso_report_iso_error(xorriso, "", ret, "Error when inquiring filter command of node", 0, "FAILURE", 1); ret= 0; goto ex; } if(ret > 0) { strcat(xorriso->result_line, ":"); Text_shellsafe(cmd->name, xorriso->result_line, 1); } if(strlen(xorriso->result_line) > SfileadrL) { Xorriso_result(xorriso, 0); xorriso->result_line[0]= 0; } } strcat(xorriso->result_line, " < "); Xorriso_stream_type(xorriso, node, stream, type_text, 0); strcat(xorriso->result_line, type_text); source_path= iso_stream_get_source_path(stream, 0); if(source_path != NULL) { strcat(xorriso->result_line, ":"); Text_shellsafe(source_path, xorriso->result_line, 1); } strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); ret= 1; ex:; if(source_path != NULL) free(source_path); return(ret); } int Xorriso_set_zisofs_params(struct XorrisO *xorriso, int flag) { int ret; struct iso_zisofs_ctrl ctrl; ctrl.version= 0; ctrl.compression_level= xorriso->zlib_level; if(xorriso->zisofs_block_size == (1 << 16)) ctrl.block_size_log2= 16; else if(xorriso->zisofs_block_size == (1 << 17)) ctrl.block_size_log2= 17; else ctrl.block_size_log2= 15; ret= iso_zisofs_set_params(&ctrl, 0); Xorriso_process_msg_queues(xorriso,0); if(ret < 0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when setting zisofs parameters", 0, "FAILURE", 1); return(0); } return(1); } int Xorriso_status_zisofs(struct XorrisO *xorriso, char *filter, FILE *fp, int flag) /* bit0= do only report non-default settings bit1= do only report to fp */ { off_t ziso_count= 0, osiz_count= 0; off_t gzip_count= 0, gunzip_count= 0; iso_zisofs_get_refcounts(&ziso_count, &osiz_count, 0); iso_gzip_get_refcounts(&gzip_count, &gunzip_count, 0); if((flag & 1) && xorriso->zlib_level == xorriso->zlib_level_default && xorriso->zisofs_block_size == xorriso->zisofs_block_size_default && xorriso->zisofs_by_magic == 0 && ziso_count == 0 && osiz_count == 0 && gzip_count == 0 && gunzip_count == 0) { if(filter == NULL) return(2); if(filter[0] == 0) return 2; } sprintf(xorriso->result_line, "-zisofs level=%d:block_size=%dk:by_magic=%s:ziso_used=%.f:osiz_used=%.f", xorriso->zlib_level, xorriso->zisofs_block_size / 1024, xorriso->zisofs_by_magic ? "on" : "off", (double) ziso_count, (double) osiz_count); sprintf(xorriso->result_line + strlen(xorriso->result_line), ":gzip_used=%.f:gunzip_used=%.f\n", (double) gzip_count, (double) gunzip_count); Xorriso_status_result(xorriso, filter, fp, flag&2); return(1); } int Xorriso_all_node_array(struct XorrisO *xorriso, int addon_nodes, int flag) { int ret; struct FindjoB *job= NULL; struct stat dir_stbuf; ret= Findjob_new(&job, "/", 0); if(ret<=0) { Xorriso_no_findjob(xorriso, "xorriso", 0); {ret= -1; goto ex;} } Findjob_set_action_target(job, 30, NULL, 0); Xorriso_destroy_node_array(xorriso, 0); ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/", &dir_stbuf, 0, 0); if(ret <= 0) goto ex; ret= Xorriso_new_node_array(xorriso, xorriso->temp_mem_limit, addon_nodes, 0); if(ret <= 0) goto ex; Findjob_set_action_target(job, 31, NULL, 0); ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/", &dir_stbuf, 0, 0); if(ret <= 0) goto ex; ret= 1; ex:; Findjob_destroy(&job, 0); return(ret); } int Xorriso_remake_hln_array(struct XorrisO *xorriso, int flag) { int ret, addon_nodes= 0, i, old_count, old_pt, new_pt; IsoNode **old_nodes; char **old_targets; /* Count hln_targets of which the node has been deleted meanwhile */ for(i= 0; i < xorriso->hln_count; i++) { if(xorriso->hln_targets[i] == NULL) continue; if(Xorriso_node_is_valid(xorriso, xorriso->hln_array[i], 0)) continue; addon_nodes++; } ret= Xorriso_all_node_array(xorriso, addon_nodes, 0); if(ret <= 0) goto ex; if(addon_nodes > 0) { /* Transfer delete nodes with hln_target to node array */ for(i= 0; i < xorriso->hln_count; i++) { if(xorriso->hln_targets[i] == NULL) continue; if(Xorriso_node_is_valid(xorriso, xorriso->hln_array[i], 0)) continue; if(xorriso->node_counter < xorriso->node_array_size) { xorriso->node_array[xorriso->node_counter++]= xorriso->hln_array[i]; iso_node_ref(xorriso->node_array[xorriso->node_counter - 1]); } } } Xorriso_sort_node_array(xorriso, 0); old_nodes= (IsoNode **) xorriso->hln_array; old_targets= (char **) xorriso->hln_targets; old_count= xorriso->hln_count; xorriso->hln_array= 0; xorriso->hln_targets= NULL; /* Transfer node_array to di_array without unrefering nodes */ xorriso->hln_count= xorriso->node_counter; xorriso->hln_array= xorriso->node_array; xorriso->node_counter= 0; xorriso->node_array_size= 0; xorriso->node_array= NULL; /* Allocate hln_targets */ ret= Xorriso_new_hln_array(xorriso, xorriso->temp_mem_limit, 1); if(ret<=0) goto ex; xorriso->node_targets_availmem= xorriso->temp_mem_limit; if(old_targets != NULL) { /* Transfer targets from old target array */; new_pt= old_pt= 0; while(new_pt < xorriso->hln_count && old_pt < old_count) { ret= Xorriso__hln_cmp(xorriso->hln_array[new_pt], old_nodes[old_pt]); if(ret < 0) { new_pt++; } else if(ret > 0) { old_pt++; } else { xorriso->hln_targets[new_pt]= old_targets[old_pt]; if(old_targets[old_pt] != NULL) xorriso->temp_mem_limit-= strlen(old_targets[old_pt]) + 1; old_targets[old_pt]= NULL; new_pt++; old_pt++; } } for(old_pt= 0; old_pt < old_count; old_pt++) if(old_targets[old_pt] != NULL) /* (should not happen) */ free(old_targets[old_pt]); free((char *) old_targets); } if(old_nodes != NULL) { for(old_pt= 0; old_pt < old_count; old_pt++) if(old_nodes[old_pt] != NULL) iso_node_unref(old_nodes[old_pt]); free((char *) old_nodes); } xorriso->hln_change_pending= 0; ret= 1; ex:; return(ret); } /* @param flag bit0= overwrite existing hln_array (else return 2) */ int Xorriso_make_hln_array(struct XorrisO *xorriso, int flag) { int ret; if(xorriso->hln_array != NULL && !(flag & 1)) { /* If no fresh image manipulations occured: keep old array */ if(!xorriso->hln_change_pending) return(2); ret= Xorriso_remake_hln_array(xorriso, 0); return(ret); } Xorriso_destroy_hln_array(xorriso, 0); ret= Xorriso_all_node_array(xorriso, 0, 0); if(ret <= 0) goto ex; Xorriso_sort_node_array(xorriso, 0); /* Transfer node_array to di_array without unrefering nodes */ xorriso->hln_count= xorriso->node_counter; xorriso->hln_array= xorriso->node_array; xorriso->node_counter= 0; xorriso->node_array_size= 0; xorriso->node_array= NULL; /* Allocate hln_targets */ ret= Xorriso_new_hln_array(xorriso, xorriso->temp_mem_limit, 1); if(ret<=0) { Xorriso_destroy_hln_array(xorriso, 0); goto ex; } xorriso->node_targets_availmem= xorriso->temp_mem_limit; xorriso->hln_change_pending= 0; ret= 1; ex:; return(ret); } /* @param flag bit0= overwrite existing di_array (else return 2) bit1= make di_array despite xorriso->ino_behavior bit 3 */ int Xorriso_make_di_array(struct XorrisO *xorriso, int flag) { int ret, bytes; #ifdef NIX /* <<< */ unsigned long old_gdic; old_gdic= Xorriso_get_di_counteR; #endif /* NIX */ if((xorriso->ino_behavior & 8 ) && !(flag & 2)) return(2); if(xorriso->di_array != NULL && !(flag & 1)) return(2); Xorriso_finish_hl_update(xorriso, 0); ret= Xorriso_all_node_array(xorriso, 0, 0); if(ret <= 0) goto ex; bytes= xorriso->node_array_size / 8 + 1; xorriso->di_do_widen= calloc(bytes, 1); if(xorriso->di_do_widen == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } /* Transfer node_array to di_array without unrefering nodes */ xorriso->di_count= xorriso->node_counter; xorriso->di_array= xorriso->node_array; xorriso->node_counter= 0; xorriso->node_array_size= 0; xorriso->node_array= NULL; Xorriso__sort_di((void *) xorriso->di_array, xorriso->di_count, 0); ret= 1; ex:; #ifdef NIX /* <<< */ fprintf(stderr, "xorriso_DEBUG: sort_count= %lu\n", Xorriso_get_di_counteR - old_gdic); #endif /* NIX */ return(ret); } /* @param flag bit0= iso_rr_path is freshly added and up to date bit2= -follow: this is not a command parameter @return -1= severe error 0= not applicable for hard links 1= go on with processing 2= iso_rr_path is fully updated */ int Xorriso_hardlink_update(struct XorrisO *xorriso, int *compare_result, char *disk_path, char *iso_rr_path, int flag) { int ret, hret, idx, low, high, i, do_overwrite= 0, did_fake_di= 0; int follow_links, old_idx= -1; IsoNode *node; struct stat stbuf; dev_t old_dev; ino_t old_ino; if(xorriso->di_array == NULL) return(1); follow_links= xorriso->do_follow_links || (xorriso->do_follow_param && !(flag & 4)); ret= Xorriso_node_from_path(xorriso, NULL, iso_rr_path, &node, 0); if(ret <= 0) return(ret); if(LIBISO_ISDIR(node)) return(1); /* Handle eventual hardlink split : */ /* This is achieved by setting the content change bit. Reason: The node needs to be removed from di_array because its di is not matching its array index any more. So it becomes invisible for the join check of eventual later hardlink siblings. Therefore it must be updated now, even if it has currently no siblings which it leaves or which it joins. */ if(!(flag & 1)) do_overwrite= 1; Xorriso__get_di(node, &old_dev, &old_ino, 0); ret= Xorriso__search_node(xorriso->di_array, xorriso->di_count, Xorriso__di_cmp, node, &idx, 0); if(ret < 0) {ret= 0; goto ex;} if(ret > 0) old_idx= idx; /* Handle eventual hardlink joining : */ if(follow_links) ret= stat(disk_path, &stbuf); else ret= lstat(disk_path, &stbuf); if(ret==-1) {ret= 0; goto ex;} /* Are there new dev-ino-siblings in the image ? */ /* Fake isofs.di */ if(!(flag & 1)) { ret= Xorriso_record_dev_inode(xorriso, disk_path, stbuf.st_dev, stbuf.st_ino, node, iso_rr_path, 1); if(ret <= 0) {ret= -1; goto ex;} did_fake_di= 1; /* temporarily remove node from di_array so it does not disturb search by its fake di info */; if(old_idx >= 0) xorriso->di_array[old_idx]= NULL; } ret= Xorriso_search_di_range(xorriso, node, &idx, &low, &high, 1); if(did_fake_di) { /* Revoke fake of isofs.di */ hret= Xorriso_record_dev_inode(xorriso, disk_path, old_dev, old_ino, node, iso_rr_path, 1); if(hret <= 0) {ret= -1; goto ex;} if(old_idx >= 0) xorriso->di_array[old_idx]= node; } if(ret == 0) {ret= 1; goto ex;} if(ret < 0) {ret= 0; goto ex;} #ifdef Xorriso_hardlink_update_debuG /* <<< */ if(low < high || idx < 0) { fprintf(stderr, "xorriso_DEBUG: old_idx= %d , low= %d , high= %d , iso= '%s' , disk='%s'\n", old_idx, low, high, iso_rr_path, disk_path); fprintf(stderr, "xorriso_DEBUG: old_dev= %lu , old_ino= %lu , dev= %lu , ino= %lu\n", (unsigned long) old_dev, (unsigned long) old_ino, (unsigned long) stbuf.st_dev, (unsigned long) stbuf.st_ino); if(idx >= 0 && idx != old_idx) fprintf(stderr, "xorriso_DEBUG: idx= %d , old_idx = %d\n", idx, old_idx); } #endif /* Xorriso_hardlink_update_debuG */ /* Overwrite all valid siblings : */ for(i= low; i <= high; i++) { if(i == idx || xorriso->di_array[i] == NULL) continue; #ifdef Xorriso_hardlink_update_debuG /* <<< */ { ino_t ino; dev_t dev; Xorriso__get_di(xorriso->di_array[i], &dev, &ino, 0); fprintf(stderr, "xorriso_DEBUG: iso_sibling= '%s' , dev= %lu , ino= %lu\n", node_path, (unsigned long) dev, (unsigned long) ino); } #endif /* Xorriso_hardlink_update_debuG */ xorriso->di_do_widen[i / 8]|= 1 << (i % 8); } ret= 1; ex:; if(do_overwrite) *compare_result|= (1<<15); if(old_idx >= 0 && (*compare_result & (3 << 21))) { /* The old di info is obsolete */ if(xorriso->di_array[old_idx] != NULL) iso_node_unref(xorriso->di_array[old_idx]); xorriso->di_array[old_idx]= NULL; } return(ret); } /* @param flag bit0= do not destroy di_array */ int Xorriso_finish_hl_update(struct XorrisO *xorriso, int flag) { int ret, zero= 0; char *argv[4]; struct Xorriso_lsT *disk_lst, *iso_lst; if(xorriso->di_array == NULL) {ret= 1; goto ex;} disk_lst= xorriso->di_disk_paths; iso_lst= xorriso->di_iso_paths; while(disk_lst != NULL && iso_lst != NULL) { argv[0]= Xorriso_lst_get_text(iso_lst, 0); argv[1]= "-exec"; argv[2]= "widen_hardlinks"; argv[3]= Xorriso_lst_get_text(disk_lst, 0); zero= 0; ret= Xorriso_option_find(xorriso, 4, argv, &zero, 0); /* -findi */ if(ret < 0) goto ex; disk_lst= Xorriso_lst_get_next(disk_lst, 0); iso_lst= Xorriso_lst_get_next(iso_lst, 0); } ret= 1; ex:; if(!(flag & 1)) Xorriso_destroy_di_array(xorriso, 0); return(ret); } /* @param flag bit0= do not report to result but only retrieve md5 text @return 1= ok, 0= no md5 available, <0= other error */ int Xorriso_get_md5(struct XorrisO *xorriso, void *in_node, char *path, char md5[16], int flag) { int ret= 1, i; char *wpt; IsoImage *image; IsoNode *node; ret= Xorriso_get_volume(xorriso, &image, 0); if(ret <= 0) goto ex; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) goto ex; } if(!LIBISO_ISREG(node)) return(0); ret= iso_file_get_md5(image, (IsoFile *) node, md5, 0); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) goto ex; if(flag & 1) {ret= 1; goto ex;} wpt= xorriso->result_line; for(i= 0; i < 16; i++) { sprintf(wpt, "%2.2x", ((unsigned char *) md5)[i]); wpt+= 2; } strcpy(wpt, " "); wpt+= 2; Xorriso_getfname(xorriso, path, 1 | 2); ret= 1; ex:; return(ret); } int Xorriso_make_md5(struct XorrisO *xorriso, void *in_node, char *path, int flag) { int ret; off_t size; IsoNode *node; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret <= 0) return(ret); } if(!LIBISO_ISREG(node)) return(0); ret= iso_file_make_md5((IsoFile *) node, 0); size= iso_file_get_size((IsoFile *) node); xorriso->pacifier_count+= size; xorriso->pacifier_byte_count+= size; Xorriso_pacifier_callback(xorriso, "content bytes read", xorriso->pacifier_count, 0, "", 0); Xorriso_process_msg_queues(xorriso, 0); if(ret < 0) { Xorriso_report_iso_error(xorriso, "", ret, "Error when computing MD5", 0, "FAILURE", 1); return(0); } Xorriso_set_change_pending(xorriso, 1); return(1); } /* @param node Opaque handle to IsoNode which is to be inquired instead of path if it is not NULL. @param path is used as address if node is NULL. @param flag bit0= do not report to result but only indicate outcome by return value bit1= silently ignore nodes without MD5 bit2= do not only report mismatches but also matches @return 3= not a data file 2= no MD5 attached to node 1= ok, MD5 compared and matching 0= not ok, MD5 mismatch <0= other error */ int Xorriso_check_md5(struct XorrisO *xorriso, void *in_node, char *path, int flag) { int ret, wanted, rret; IsoImage *image; IsoNode *node; IsoFile *file; char node_md5[16], data_md5[16], buffer[64 * 1024]; void *stream= NULL, *ctx= NULL; off_t todo; node= (IsoNode *) in_node; if(node == NULL) { ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0); if(ret<=0) {ret= -1; goto ex;} } if(!LIBISO_ISREG(node)) { strcpy(xorriso->info_text, "-check_md5: Not a data file: "); Text_shellsafe(path, xorriso->info_text, 1); if(!(flag & 2)) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= 3; goto ex; } file= (IsoFile *) node; /* obtain MD5 */ ret= Xorriso_get_volume(xorriso, &image, 0); if(ret <= 0) {ret= -1; goto ex;} ret= iso_file_get_md5(image, file, node_md5, 0); Xorriso_process_msg_queues(xorriso,0); if(ret < 0) {ret= -1; goto ex;} if(ret == 0) { strcpy(xorriso->info_text, "-check_md5: No MD5 recorded with file: "); Text_shellsafe(path, xorriso->info_text, 1); if(!(flag & 2)) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); ret= 2; goto ex; } /* Read file and compute MD5 */; ret= Xorriso_iso_file_open(xorriso, path, (void *) node, &stream, 1 | 2); if(ret <= 0) {ret= -1; goto ex;} ret= iso_md5_start(&ctx); if(ret < 0) goto ex; todo= iso_stream_get_size(stream); while(todo > 0) { if(todo < sizeof(buffer)) wanted= todo; else wanted= sizeof(buffer); rret = Xorriso_iso_file_read(xorriso, stream, buffer, wanted, 0); if(rret <= 0) {ret= -1; goto ex;} todo-= rret; ret = iso_md5_compute(ctx, buffer, rret); if(ret < 0) goto ex; xorriso->pacifier_count+= rret; xorriso->pacifier_byte_count+= rret; Xorriso_pacifier_callback(xorriso, "content bytes read", xorriso->pacifier_count, 0, "", 0); } ret= iso_md5_end(&ctx, data_md5); if(ret < 0) goto ex; /* Report outcome */ Xorriso_process_msg_queues(xorriso,0); if(! iso_md5_match(node_md5, data_md5)) { sprintf(xorriso->result_line, "MD5 MISMATCH: "); Text_shellsafe(path, xorriso->result_line, 1); strcat(xorriso->result_line, "\n"); if(!(flag & 1)) Xorriso_result(xorriso,0); ret= 0; } else { sprintf(xorriso->result_line, "md5 match : "); Text_shellsafe(path, xorriso->result_line, 1); strcat(xorriso->result_line, "\n"); if(flag & 4) Xorriso_result(xorriso,0); ret= 1; } ex:; Xorriso_process_msg_queues(xorriso,0); Xorriso_iso_file_close(xorriso, &stream, 0); if(ctx != NULL) iso_md5_end(&ctx, data_md5); if(ret < 0) { sprintf(xorriso->result_line, "NOT READABLE: "); Text_shellsafe(path, xorriso->result_line, 1); strcat(xorriso->result_line, "\n"); if(!(flag & 1)) Xorriso_result(xorriso,0); } return(ret); } int Xorriso_check_md5_range(struct XorrisO *xorriso, off_t start_lba, off_t end_lba, char md5[16], int flag) { int ret; struct burn_drive_info *dinfo= NULL; struct burn_drive *drive= NULL; off_t pos, data_count, to_read; char data[64 * 1024], data_md5[16]; void *ctx = NULL; ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to check session MD5 checksum", 0); if(ret <= 0) goto ex; ret= iso_md5_start(&ctx); if(ret <= 0) { Xorriso_no_malloc_memory(xorriso, NULL, 0); goto ex; } for(pos= start_lba; pos < end_lba; pos+= 32) { to_read= 32; if(pos + to_read > end_lba) to_read= end_lba - pos; ret= burn_read_data(drive, pos * (off_t) 2048, data, to_read * (off_t) 2048, &data_count, 0); if(ret <= 0) goto ex; iso_md5_compute(ctx, data, (int) data_count); xorriso->pacifier_count+= data_count; xorriso->pacifier_byte_count+= data_count; Xorriso_pacifier_callback(xorriso, "content bytes read", xorriso->pacifier_count, 0, "", 0); } iso_md5_end(&ctx, data_md5); ret= 1; if(! iso_md5_match(md5, data_md5)) ret= 0; ex:; Xorriso_process_msg_queues(xorriso,0); if(ctx != NULL) iso_md5_end(&ctx, data_md5); return(ret); } int Xorriso_check_session_md5(struct XorrisO *xorriso, char *severity, int flag) { int ret, i; IsoImage *image; uint32_t start_lba, end_lba; char md5[16], md5_text[33]; ret= Xorriso_get_volume(xorriso, &image, 0); if(ret<=0) return(ret); ret= iso_image_get_session_md5(image, &start_lba, &end_lba, md5, 0); Xorriso_process_msg_queues(xorriso,0); if(ret < 0) return(ret); if(ret == 0) { sprintf(xorriso->info_text, "No session MD5 is recorded with the loaded session"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0); return(0); } sprintf(xorriso->info_text, "Checking loaded session by its recorded MD5.\n"); Xorriso_info(xorriso, 0); for(i= 0; i < 16; i++) sprintf(md5_text + 2 * i, "%2.2x", ((unsigned char *) md5)[i]); sprintf(xorriso->result_line, "Session MD5 %s , LBA %.f , %.f blocks\n", md5_text, (double) start_lba, (double) end_lba - start_lba); Xorriso_result(xorriso,0); ret= Xorriso_check_md5_range(xorriso, (off_t) start_lba, (off_t) end_lba, md5, 0); return(ret); } int Xorriso_image_has_md5(struct XorrisO *xorriso, int flag) { int ret; IsoImage *image; uint32_t start_lba, end_lba; char md5[16]; ret= Xorriso_get_volume(xorriso, &image, 0); if(ret<=0) return(ret); ret= iso_image_get_session_md5(image, &start_lba, &end_lba, md5, 0); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) return(0); return(1); } int Xorriso_md5_start(struct XorrisO *xorriso, void **ctx, int flag) { int ret; ret= iso_md5_start(ctx); if(ret == 1) return(1); Xorriso_no_malloc_memory(xorriso, NULL, 0); return(-1); } int Xorriso_md5_compute(struct XorrisO *xorriso, void *ctx, char *data, int datalen, int flag) { iso_md5_compute(ctx, data, datalen); return(1); } int Xorriso_md5_end(struct XorrisO *xorriso, void **ctx, char md5[16], int flag) { int ret; ret= iso_md5_end(ctx, md5); Xorriso_process_msg_queues(xorriso,0); if(ret <= 0) return(0); return(1); } /* @param flag bit0=input drive bit1=output drive bit2= wake up rather than calm down */ int Xorriso_drive_snooze(struct XorrisO *xorriso, int flag) { int in_is_out_too, ret; struct burn_drive_info *dinfo; struct burn_drive *drive; in_is_out_too= (xorriso->in_drive_handle == xorriso->out_drive_handle); if((flag & 1) && xorriso->in_drive_handle != NULL) { Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to calm drive", 0); burn_drive_snooze(drive, !!(flag & 4)); if(in_is_out_too) {ret= 1; goto ex;} } if((flag&2) && xorriso->out_drive_handle!=NULL) { Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "on attempt to calm drive", 2); burn_drive_snooze(drive, !!(flag & 4)); } ret= 1; ex:; Xorriso_process_msg_queues(xorriso,0); return(ret); } int Xorriso_pvd_info(struct XorrisO *xorriso, int flag) { int ret, msc1= -1, msc2, i; IsoImage *image; struct burn_drive_info *dinfo; struct burn_drive *drive; char *msg, block_head[8]; off_t head_count; msg= xorriso->result_line; ret= Xorriso_get_volume(xorriso, &image, 0); if(ret<=0) return(ret); ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, "", 16); if(ret > 0) { ret= Xorriso_msinfo(xorriso, &msc1, &msc2, 1 | 4); if(ret<0) return(ret); Xorriso_toc(xorriso, 128); if(msc1 >= 0) { for(i = msc1 + 16; i < msc1 + 32; i++) { ret= burn_read_data(drive, (off_t) i * (off_t) 2048, block_head, (off_t) sizeof(block_head), &head_count, 2); if(ret <= 0) { i= msc1 + 32; break; } if(block_head[0] == 1 && strncmp(block_head + 1, "CD001", 5) == 0) break; } if(i < msc1 + 32) { sprintf(msg, "PVD address : %ds\n", i); Xorriso_result(xorriso,0); } } } sprintf(msg, "Volume Id : %s\n", un0(iso_image_get_volume_id(image))); Xorriso_result(xorriso,0); sprintf(msg, "Volume Set Id: %s\n", xorriso->volset_id); Xorriso_result(xorriso,0); sprintf(msg, "Publisher Id : %s\n", xorriso->publisher); Xorriso_result(xorriso,0); sprintf(msg, "Preparer Id : %s\n", un0(iso_image_get_data_preparer_id(image))); Xorriso_result(xorriso,0); sprintf(msg, "App Id : %s\n", xorriso->application_id); Xorriso_result(xorriso,0); sprintf(msg, "System Id : %s\n", xorriso->system_id); Xorriso_result(xorriso,0); sprintf(msg, "Copyright Id : %s\n", un0(iso_image_get_copyright_file_id(image))); Xorriso_result(xorriso,0); sprintf(msg, "Abstract Id : %s\n", un0(iso_image_get_abstract_file_id(image))); Xorriso_result(xorriso,0); sprintf(msg, "Biblio Id : %s\n", un0(iso_image_get_biblio_file_id(image))); Xorriso_result(xorriso,0); return(1); } /* @param flag bit0= do not set hln_change_pending */ int Xorriso_set_change_pending(struct XorrisO *xorriso, int flag) { int ret; IsoImage *image; ret= Xorriso_get_volume(xorriso, &image, 1); if(ret <= 0) return ret; xorriso->volset_change_pending= 1; if(!(flag & 1)) xorriso->hln_change_pending= 1; return(1); } /* @param flag bit0= enable SCSI command logging to stderr */ int Xorriso_scsi_log(struct XorrisO *xorriso, int flag) { if(flag == 0) burn_set_scsi_logging(0); else burn_set_scsi_logging(2|4); return(1); }