/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images. Copyright 2007-2010 Thomas Schmitt, Provided under GPL version 2 or later. This file contains functions which manipulate the libisofs tree model. */ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "xorriso.h" #include "xorriso_private.h" #include "xorrisoburn.h" #include "lib_mgt.h" #include "iso_img.h" #include "iso_tree.h" #include "iso_manip.h" #include "sort_cmp.h" /* @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= 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 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); } /* @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); } int Xorriso_set_st_mode(struct XorrisO *xorriso, char *in_path, mode_t mode_and, mode_t mode_or, int flag) { mode_t mode= 0; int ret; IsoNode *node; char sfe[5*SfileadrL], path[SfileadrL]; ret= Xorriso_get_node_by_path(xorriso, in_path, path, &node, 0); if(ret<=0) return(ret); mode= iso_node_get_permissions(node); mode= (mode & mode_and) | mode_or; iso_node_set_permissions(node, mode); iso_node_set_ctime(node, time(NULL)); sprintf(xorriso->info_text,"Permissions now: %-5.5o %s", (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); } /* 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 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 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 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); } /* @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); } int Xorriso_set_hidden(struct XorrisO *xorriso, void *in_node, char *path, int hide_state, int flag) { int ret, hide_attrs= 0; 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(hide_state) { hide_attrs|= LIBISO_HIDE_BUT_WRITE; if(hide_state & 1) hide_attrs|= LIBISO_HIDE_ON_RR; if(hide_state & 2) hide_attrs|= LIBISO_HIDE_ON_JOLIET; } iso_node_set_hidden(node, hide_attrs); 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); } /* The caller shall make no assumptions about the meaning of iter, node_array, node_count, node_idx ! They are just opaque handles for which the caller provides the memory of proper type. @param flag bit0= initialize iteration bit1= action needs full freedom of object manipulation bit2= action needs LBA sorted iteration bit31= end iteration (mandatory !) */ int Xorriso_findi_iter(struct XorrisO *xorriso, IsoDir *dir_node, off_t *mem, IsoDirIter **iter, IsoNode ***node_array, int *node_count, int *node_idx, IsoNode **iterated_node, int flag) { int ret, i; IsoNode *node; off_t new_mem= 0; char mem_text[80], limit_text[80]; if(flag&1) { *node_array= NULL; *node_count= -1; *node_idx= 0; *iter= NULL; ret= iso_dir_get_children(dir_node, iter); if(ret<0) { cannot_iter:; Xorriso_cannot_create_iter(xorriso, ret, 0); return(-1); } if((flag&2)|(flag&4)) { /* copy list of nodes and prepare soft iterator */ *node_count= 0; while(iso_dir_iter_next(*iter, &node) == 1) (*node_count)++; iso_dir_iter_free(*iter); *iter= NULL; new_mem= ((*node_count)+1) * sizeof(IsoNode *); if(new_mem > xorriso->temp_mem_limit) { Sfile_scale((double) new_mem, mem_text, 5,1e4, 0); Sfile_scale((double) xorriso->temp_mem_limit, limit_text, 5,1e4, 0); sprintf(xorriso->info_text, "Stacked directory snapshots exceed -temp_mem_limit (%s > %s)", mem_text, limit_text); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); *node_count= -1; return(-1); } (*node_array)= (IsoNode **) calloc((*node_count)+1, sizeof(IsoNode *)); if(*node_array == NULL) { sprintf(xorriso->info_text, "Could not allocate inode list of %.f bytes", ((double) (*node_count)+1) * (double) sizeof(IsoNode *)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0); *node_count= -1; return(-1); } *mem= new_mem; ret= iso_dir_get_children(dir_node, iter); if(ret<0) goto cannot_iter; while(iso_dir_iter_next(*iter, &node) == 1 && *node_idx < *node_count) { (*node_array)[*node_idx]= node; iso_node_ref(node); (*node_idx)++; } iso_dir_iter_free(*iter); *iter= NULL; *node_count= *node_idx; *node_idx= 0; if((flag&4) && *node_count>1) qsort(*node_array, *node_count, sizeof(IsoNode *), Xorriso__node_lba_cmp); } } if(flag&(1<<31)) { if(*node_count>=0 && *node_array!=NULL) { for(i= 0; i<*node_count; i++) iso_node_unref((*node_array)[i]); free(*node_array); *node_array= NULL; *node_count= -1; *node_idx= 0; } else { if(*iter!=NULL) iso_dir_iter_free(*iter); *iter= NULL; } } if(flag&(1|(1<<31))) return(1); if(*node_count>=0) { /* return next node_array element */ if(*node_idx>=*node_count) return(0); *iterated_node= (*node_array)[*node_idx]; (*node_idx)++; } else { ret= iso_dir_iter_next(*iter, iterated_node); return(ret == 1); } return(1); } /* @param flag bit0= 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 if(action == 39) { /* hide */ Xorriso_set_hidden(xorriso, node, NULL, type, 0); } 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_disk_name(struct XorrisO *xorriso, struct ExprtesT *ftest, IsoNode *node, int flag) { int ret; char disk_path[SfileadrL], *npt; regmatch_t name_match; void *arg2; ret= Xorriso_retrieve_disk_path(xorriso, node, disk_path, 0); if(ret <= 0) return(0); arg2= ftest->arg2; npt= strrchr(disk_path, '/'); if(npt != NULL) npt++; else npt= disk_path; ret= regexec(arg2, npt, 1, &name_match, 0); return !ret; } 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, mask; 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; case 16: /* -disk_name *arg1 (regex in *arg2) */ value= !! Exprtest_match_disk_name(xorriso, ftest, node, 0); break; case 17: /* -hidden int *arg1 */ value= 0; ret= iso_node_get_hidden(node); mask= *((int *) arg1) & 3; if(mask == 0 && !(ret & (LIBISO_HIDE_ON_RR | LIBISO_HIDE_ON_JOLIET))) value= 1; else if(mask == 1 && (ret & LIBISO_HIDE_ON_RR)) value= 1; else if(mask == 2 && (ret & LIBISO_HIDE_ON_JOLIET)) value= 1; else if(mask == 3 && (ret & LIBISO_HIDE_ON_RR) && (ret & LIBISO_HIDE_ON_JOLIET)) value= 1; 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); } /* @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); } 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_perform_acl_from_list(struct XorrisO *xorriso, char *file_path, char *uid, char *gid, char *acl, int flag) { int ret, zero= 0; uid_t uid_number; gid_t gid_number; /* Set group and owner */ if(gid[0]) { ret= Xorriso_convert_gidstring(xorriso, gid, &gid_number, 0); if(ret<=0) return(ret); ret= Xorriso_set_gid(xorriso, file_path, gid_number, 0); if(ret<=0) return(ret); } if(uid[0]) { ret= Xorriso_convert_uidstring(xorriso, uid, &uid_number, 0); if(ret<=0) return(ret); ret= Xorriso_set_uid(xorriso, file_path, uid_number, 0); if(ret<=0) return(ret); } ret= Xorriso_option_setfacli(xorriso, acl, 1, &file_path, &zero, 0); if(ret <= 0) return(ret); return(1); } /* @param flag bit0= do not perform setfattr but only check input */ int Xorriso_path_setfattr(struct XorrisO *xorriso, void *in_node, char *path, char *name, size_t value_length, char *value, int flag) { int ret, hflag; size_t num_attrs= 1; char *name_pt; hflag= 2; name_pt= name; if(name[0] == 0) { sprintf(xorriso->info_text, "-setfattr: Empty attribute name is not allowed"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0); return(0); } else if(strcmp(name, "--remove-all") == 0) { if(value[0]) { sprintf(xorriso->info_text, "-setfattr: Value is not empty with pseudo name --remove-all"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0); return(0); } num_attrs= 0; hflag= 0; } else if(name[0] == '-') { name_pt++; hflag|= 4; } else if(name[0] == '=' || name[0] == '+') { name_pt++; } if(flag & 1) return(1); ret= Xorriso_setfattr(xorriso, in_node, path, num_attrs, &name_pt, &value_length, &value, hflag); return(ret); } /* Warning: The text content of lst gets mangled by 0s and unescaping. */ int Xorriso_perform_attr_from_list(struct XorrisO *xorriso, char *path, struct Xorriso_lsT *lst_start, int flag) { int ret, eaten; char *valuept, *ept, *line, **names= NULL, **values= NULL; size_t num_attr= 0, *value_lengths= NULL, v_len; struct Xorriso_lsT *lst; for(lst= lst_start; lst != NULL; lst= Xorriso_lst_get_next(lst, 0)) num_attr++; if(num_attr == 0) { ret= Xorriso_setfattr(xorriso, NULL, path, num_attr, NULL, NULL, NULL, 0); goto ex; } names= calloc(num_attr, sizeof(char *)); if(names == NULL) { Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } value_lengths= calloc(num_attr, sizeof(size_t)); if(value_lengths== NULL) { free(names); Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } values= calloc(num_attr, sizeof(char *)); if(values== NULL) { free(names); free(value_lengths); Xorriso_no_malloc_memory(xorriso, NULL, 0); ret= -1; goto ex; } num_attr= 0; for(lst= lst_start; lst != NULL; lst= Xorriso_lst_get_next(lst, 0)) { line= Xorriso_lst_get_text(lst, 0); ept= strchr(line, '='); if(ept == NULL) continue; /* Split into name and content */; *ept= 0; valuept= ept + 1; /* Strip quotes from value */ v_len= strlen(valuept); if(v_len < 2 || *valuept != '"' || *(valuept + v_len - 1) != '"') continue; *valuept= 0; *(valuept + v_len - 1)= 0; valuept++; v_len-= 2; /* Unescape backslashes , values eventually with 0-bytes */ ret= Sfile_bsl_interpreter(line, strlen(line), &eaten, 0); if(ret <= 0) continue; ret= Sfile_bsl_interpreter(valuept, (int) v_len, &eaten, 2); if(ret <= 0) continue; names[num_attr]= line; values[num_attr]= valuept; value_lengths[num_attr]= v_len - eaten; num_attr++; } ret= Xorriso_setfattr(xorriso, NULL, path, num_attr, names, value_lengths, values, 0); ex:; if(names != NULL) free(names); if(value_lengths != NULL) free(value_lengths); if(values != NULL) free(values); return(ret); }