/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images. Copyright 2007-2016 Thomas Schmitt, Provided under GPL version 2 or later. This file contains functions which access nodes of the libisofs tree model. */ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include #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 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= do not use libisofs (work literally or in disk world) bit2= (implies 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= NULL, *apt, *npt, *cpt, *link_target= NULL; Xorriso_alloc_meM(path, char, SfileadrL); Xorriso_alloc_meM(link_target, char, SfileadrL); if(flag & 4) flag|= 2; if((flag&64) || !(flag&2)) { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; } eff_path[0]= 0; if(img_path[0]==0) { if(flag&8) strcpy(eff_path, "/"); {ret= 2; goto ex;} /* 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) {ret= -1; goto ex;} 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); {ret= -1; goto ex;} } else if(path[1]==0) { if(flag&8) strcpy(eff_path, "/"); {ret= 2; goto ex;} /* root directory */ } if(apt[0] == '.') if(apt[1] == 0 || apt[1] == '/') is_dir= 1; 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) 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: "); Text_shellsafe(img_path, xorriso->info_text, 1); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= -1; goto ex;} } dir= iso_node_get_parent(node); /* >>> Get absolute path of node as eff_path, to avoid link problems */; } if(flag & 4) { /* Linux-ish local filesystem semantics: If the parent is a symbolic link, do not ascend to its parent, but to the parent of the link target. >>> ??? Are there systems which do it differently ? */ if(Sfile_type(eff_path, 0) == 3) { ret= Xorriso_resolve_link(xorriso, eff_path, link_target, 2); if(ret <= 0) {ret= -1; goto ex;} strcpy(eff_path, link_target); } } /* 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; } is_dir= 0; 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); {ret= -1; goto ex;} } if(!(flag&2)) { dir= (IsoDir *) node; ret= Xorriso_node_from_path(xorriso, volume, eff_path, &node, flag&1); if(ret<=0) {ret= 0; goto ex;} 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) {ret= 0; goto ex;} if(ret==2) is_dir= 1; else is_dir= 0; } ret= 1+!!is_dir; ex:; Xorriso_free_meM(path); Xorriso_free_meM(link_target); return(ret); } int Xorriso_get_node_by_path(struct XorrisO *xorriso, char *in_path, char *eff_path, IsoNode **node, int flag) { int ret; char *path= NULL; IsoImage *volume; Xorriso_alloc_meM(path, char, SfileadrL); ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, in_path, path, 0); if(ret<=0) goto ex; if(eff_path!=NULL) strcpy(eff_path, path); ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; ret= Xorriso_node_from_path(xorriso, volume, path, node, 0); if(ret<=0) {ret= 0; goto ex;} ret= 1; ex:; Xorriso_free_meM(path); return(ret); } /* @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 bit5= do not look for truncated versions of path component */ 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; IsoBoot *bootcat; uint32_t lba; char *catcontent = NULL; off_t catsize; dev_t dev_number; 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) & 2) | !(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, &dev_number, 0); stbuf->st_rdev= dev_number; } else if(LIBISO_ISBLK(*node)) { stbuf->st_mode|= S_IFBLK; /* ts B11124: Debian mips and mipsel have sizeof(stbuf.st_rdev) == 4 whereas sizeof(dev_t) is 8. This workaround assumes that the returned numbers fit into 4 bytes. The may stem from the local filesystem or from the ISO image. At least there will be no memory corruption but only an integer rollover. */ Xorriso_node_get_dev(xorriso, *node, path, &dev_number, 0); stbuf->st_rdev= dev_number; } 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 if(LIBISO_ISBOOT(*node)) { ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret <= 0) return(-1); ret= iso_image_get_bootcat(volume, &bootcat, &lba, &catcontent, &catsize); if(catcontent != NULL) free(catcontent); if(ret < 0) { Xorriso_process_msg_queues(xorriso,0); return(-1); } stbuf->st_size= catsize; } 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); } 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= in_node is valid, do not resolve iso_adr bit2= recognize and parse split parts despite xorrio->split_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 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) { if(result_len == 0) break; *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)) { if(Sfile_str(xorriso->result_line, cpt, 0) <= 0) goto too_long; 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) if(Sfile_str(xorriso->result_line, "default:", 0) <= 0) goto too_long; if(Sfile_str(xorriso->result_line, cpt, 1) <= 0) goto too_long; 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'; } } } if(result_len == 0) { if(acl_text != NULL) *acl_text= NULL; ret= 2; } else { ret= 1; } ex:; iso_node_get_acl_text(node, &text, &d_text, 1 << 15); return(ret); too_long: Xorriso_msgs_submit(xorriso, 0, "Oversized ACL", 0, "FAILURE", 0); ret= 0; goto ex; } /* @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 < (int) 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 flag bit0= with mode "e" : Use echo -e encoding but do not put out commands and quotation marks. Rather apply double backslash. */ int Xorriso_append_extattr_comp(struct XorrisO *xorriso, char *comp, size_t comp_len, char *mode, int flag) { int ret; size_t line_limit; char *line, *wpt, *bsl = NULL; unsigned char *upt, *uval; line= xorriso->result_line; line_limit= sizeof(xorriso->result_line); uval= (unsigned char *) comp; if(*mode == 'q') { Text_shellsafe(comp, line, 1); } else if(*mode == 'e' || mode[0] == 0) { for(upt= uval; (size_t) (upt - uval) < comp_len; upt++) if(*upt <= 037 || *upt >= 0177) break; if((size_t) (upt - uval) < comp_len || (flag & 1)) { /* Use "$(echo -e '\0xyz')" */; if(!(flag & 1)) strcat(line, "\"$(echo -e '"); wpt= line + strlen(line); for(upt= uval; (size_t) (upt - uval) < comp_len; upt++) { if(wpt - line + 5 + 3 + 1 > (ssize_t) line_limit) /* "\\0xyz" + "')\"" + 0 */ goto too_much; if(*upt <= 037 || *upt >= 0177 || *upt == '\\' || *upt == '\'') { if(flag & 1) *(wpt++)= '\\'; sprintf((char *) wpt, "\\0%-3.3o", *upt); wpt+= strlen(wpt); } else { *(wpt++)= *upt; } } *wpt= 0; if(!(flag & 1)) strcpy(wpt, "')\""); } else { Text_shellsafe(comp, line, 1); } } else if(*mode == 'b') { ret= Sfile_bsl_encoder(&bsl, comp, comp_len, 8); if(ret <= 0) {ret= -1; goto ex;} if(strlen(line) + strlen(bsl) + 1 > line_limit) goto too_much; strcat(line, bsl); free(bsl); bsl= NULL; } else if(*mode == 'r') { if(strlen(line) + strlen(comp) + 1 > line_limit) goto too_much; strcat(line, comp); } ret= 1; ex:; if(bsl != NULL) free(bsl); return(ret); too_much:; Xorriso_msgs_submit(xorriso, 0, "Oversized BSD-style file attribute", 0, "FAILURE", 0); ret= -1; goto ex; } /* @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 */ int Xorriso_list_extattr(struct XorrisO *xorriso, void *in_node, char *path, char *show_path, char *mode, int flag) { int ret= 1, i, bsl_mem; size_t num_attrs= 0, *value_lengths= NULL; char **names= NULL, **values= NULL, *cpt, *space_pt, *name_pt, *path_pt; char *line; unsigned char *upt, *uval; line= xorriso->result_line; 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;} strcpy(line, "n="); path_pt= show_path + (show_path[0] == '/'); if(path_pt[0] == 0) path_pt= "."; ret= Xorriso_append_extattr_comp(xorriso, path_pt, strlen(path_pt), mode, 0); if(ret <= 0) goto ex; strcat(line, "\n"); Xorriso_result(xorriso, 0); for(i= 0; i < (int) num_attrs; i++) { line[0]= 0; uval= (unsigned char *) values[i]; if(strlen(names[i]) + value_lengths[i] >= SfileadrL) { sprintf(line, "echo 'OMITTED: Oversized: name %d bytes, value %d bytes in file '\"$n\" >&2\n", (int) strlen(names[i]), (int) value_lengths[i]); Xorriso_result(xorriso, 0); continue; } /* Form: $c space name value $n */ /* Split namespace from name */ cpt= strchr(names[i], '.'); if(cpt == NULL) { space_pt= "user"; name_pt= names[i]; } else { *cpt= 0; space_pt= names[i]; name_pt= cpt + 1; } /* FreeBSD setextattr cannot set 0-bytes */ for(upt= uval; (size_t) (upt - uval) < value_lengths[i]; upt++) if(*upt == 0 ) break; if((size_t) (upt - uval) < value_lengths[i]) { strcpy(line, "echo 'OMITTED: Value contains 0-bytes : space \"'\""); ret= Xorriso_append_extattr_comp(xorriso, space_pt, strlen(space_pt), "e", 1); if(ret <= 0) goto ex; strcat(line, "\"'\" , name \"'\""); ret= Xorriso_append_extattr_comp(xorriso, name_pt, strlen(name_pt), "e", 1); if(ret <= 0) goto ex; strcat(line, "\"'\" in file '\""); ret= Xorriso_append_extattr_comp(xorriso, path_pt, strlen(path_pt), "e", 1); if(ret <= 0) goto ex; strcat(line, "\" >&2\n"); /* 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; strcpy(line, "# "); } strcat(line, "$c "); ret= Xorriso_append_extattr_comp(xorriso, space_pt, strlen(space_pt), mode, 0); if(ret <= 0) goto ex; strcat(line, " "); ret= Xorriso_append_extattr_comp(xorriso,name_pt, strlen(name_pt), mode, 0); if(ret <= 0) goto ex; strcat(line, " "); ret= Xorriso_append_extattr_comp(xorriso, values[i], value_lengths[i], mode, 0); if(ret <= 0) goto ex; strcat(line, " \"$n\"\n"); /* 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; } strcpy(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 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 < (int) *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); } 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); } /* @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, "", 8); 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 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; Xorriso_alloc_meM(sfe, char, 5 * SfileadrL); Xorriso_alloc_meM(path, char, SfileadrL); Xorriso_alloc_meM(show_path, char, SfileadrL); *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*1024sh_style_result) sprintf(xorriso->result_line, "%-7.f ",(double) (report_size)); else sprintf(xorriso->result_line, "%7.f ",(double) (report_size)); sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n", Xorriso_esc_filepath(xorriso, show_path, sfe, 0)); Xorriso_result(xorriso, 0); } ret= 1; ex:; Xorriso_free_meM(sfe); Xorriso_free_meM(path); Xorriso_free_meM(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; j xorriso->file_name_limit) { ended= 0; break; } if(*rpt == '/') rpt++; } if(ended) return(1); /* All short enough */ /* Some truncation is needed */ buffer[0]= 0; wpt= buffer; if(path[0] == '/') *(wpt++)= '/'; rpt= path; if(*rpt == '/') rpt++; for(ended= 0; !ended;) { basrpt= rpt; baswpt= wpt; rpt= strchr(basrpt, '/'); if(rpt == NULL) { rpt= basrpt + strlen(basrpt); ended= 1; } skip= 0; for(cpt= basrpt; cpt < rpt; cpt++) { *(wpt++)= *cpt; if((flag & 1) && strchr("*?[", *cpt) != NULL) skip= 1; } *wpt= 0; if((!skip) && rpt - basrpt > xorriso->file_name_limit) { ret= iso_truncate_leaf_name(1, xorriso->file_name_limit, baswpt, 0); Xorriso_process_msg_queues(xorriso, 0); if(ret < 0) return(0); wpt= baswpt + strlen(baswpt); } if(!ended) { *(wpt++)= '/'; rpt++; } } *resultpt= buffer; return(1); } /* @param flag bit0= long format bit1= do not print count of nodes bit2= du format bit3= print directories as themselves (ls -d) bit5= do not look for truncated versions of path component */ int Xorriso_ls_filev(struct XorrisO *xorriso, char *wd, int filec, char **filev, off_t boss_mem, int flag) { int i, ret, was_error= 0, dfilec= 0, pass, passes, hidden_state= 0; IsoNode *node; IsoImage *volume; char *path= NULL, *link_target= NULL, *rpt, **dfilev= NULL; char *a_text= NULL, *d_text= NULL, *namept; off_t size; struct stat stbuf; Xorriso_alloc_meM(path, char, SfileadrL); Xorriso_alloc_meM(link_target, char, SfileadrL); rpt= xorriso->result_line; ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) goto ex; Sort_argv(filec, filev, 0); /* Count valid nodes, warn of invalid ones */ for(i= 0; i> 4) & 2)); if(ret<=0) { sprintf(xorriso->info_text, "Not found in ISO image: "); Text_shellsafe(path, xorriso->info_text, 1); 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) {ret= !was_error; goto ex;} } 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); Xorriso_esc_filepath(xorriso, filev[i], xorriso->result_line, 0); strcat(xorriso->result_line, ":\n"); 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); hidden_state= Xorriso_node_eff_hidden(xorriso, node, 0); ret= Xorriso_format_ls_l(xorriso, &stbuf, 1 | ((a_text != NULL || d_text != NULL) << 1) | (hidden_state << 2)); 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) {ret= -1; goto ex;} if(ret==0) continue; } if(xorriso->sh_style_result) sprintf(rpt, "%-7.f ",(double) (size/1024)); else sprintf(rpt, "%7.f ",(double) (size/1024)); } Xorriso_truncate_path_comps(xorriso, filev[i], path, &namept, 0); if(link_target[0] && (flag&5)==1) { Xorriso_esc_filepath(xorriso, namept, xorriso->result_line, 1); strcat(xorriso->result_line, " -> "); Xorriso_esc_filepath(xorriso, link_target, xorriso->result_line, 1 | 2); } else { Xorriso_esc_filepath(xorriso, namept, xorriso->result_line, 1); } strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); } ret= !was_error; ex:; Xorriso_free_meM(path); Xorriso_free_meM(link_target); return(ret); } /* 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, i, filec= 0, failed_at, no_sort= 0; IsoNode *node, **node_array= NULL; IsoDir *dir_node; IsoDirIter *iter= NULL; char *link_target= NULL, *npt, *rpt; struct stat stbuf; Xorriso_alloc_meM(link_target, char, SfileadrL); rpt= xorriso->result_line; ret= Xorriso_dir_from_path(xorriso, "Working directory", xorriso->wdi, &dir_node, 0); if(ret <= 0) goto ex; 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)) { Xorriso_esc_filepath(xorriso, npt, xorriso->result_line, 1); strcat(xorriso->result_line, " -> "); Xorriso_esc_filepath(xorriso, link_target, xorriso->result_line, 1 | 2); } else { Xorriso_esc_filepath(xorriso, npt, xorriso->result_line, 1); } strcat(xorriso->result_line, "\n"); 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); Xorriso_free_meM(link_target); return(ret); } /* @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 bit2= do not issue debug messages about temporay memory needs */ 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; 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 "); Text_shellsafe(patterns[i], xorriso->info_text, 1); strcat(xorriso->info_text, " : Working directory does not exist in ISO image"); 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, !!(flag & 4)); if(ret<=0) goto ex; /* now store addresses */ for(i= 0; i= SfileadrL) { free(source_path); return(0); } strcpy(disk_path, source_path); free(source_path); return(1); } /* @param flag bit0= show numbers from iso_stream_get_id */ 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; unsigned int fs_id; dev_t dev_id; ino_t ino_id; 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); if(flag & 1) { iso_stream_get_id(stream, &fs_id, &dev_id, &ino_id); sprintf(xorriso->result_line + strlen(xorriso->result_line), "[%u,%lu,%lu]", fs_id, (unsigned long) dev_id, (unsigned long) ino_id); } 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); if(flag & 1) { iso_stream_get_id(stream, &fs_id, &dev_id, &ino_id); sprintf(xorriso->result_line + strlen(xorriso->result_line), "[%u,%lu,%lu]", fs_id, (unsigned long) dev_id, (unsigned long) ino_id); } 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); } /* @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, *section_sizes= NULL; 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, §ion_sizes, &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(section_sizes != NULL) free((char *) section_sizes); if(*damage_start < 0) return(0); return(1); } /* @param flag bit0= report_sections : section size rather than total size bit1= last_data_file_block : looking for highest data file block */ int Xorriso_report_lba(struct XorrisO *xorriso, char *show_path, IsoNode *node, uint32_t *last_block, int flag) { int ret, *start_lbas= NULL, *end_lbas= NULL, lba_count, i; off_t size, *section_sizes= NULL; ret= Xorriso__start_end_lbas(node, &lba_count, &start_lbas, &end_lbas, §ion_sizes, &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++) { if(flag & 1) size= section_sizes[i]; if(flag & 2) { if(end_lbas[i] > 0 && (uint32_t) end_lbas[i] > *last_block) *last_block= end_lbas[i]; } else { sprintf(xorriso->result_line, "File data lba: %2d , %8d , %8d , %8.f , ", i, start_lbas[i], end_lbas[i] + 1 - start_lbas[i], (double) size); Text_shellsafe(show_path, xorriso->result_line, 1); strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); } } ret= 1; ex:; if(start_lbas != NULL) free((char *) start_lbas); if(end_lbas != NULL) free((char *) end_lbas); if(section_sizes != NULL) free((char *) section_sizes); 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; 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 , ", (double) damage_start, (double) (damage_end - damage_start) , (double) size); } else { sprintf(xorriso->result_line, "File seems ok: %8.f , %8.f , %8.f , ", -1.0, -1.0, (double) size); } Text_shellsafe(show_path, xorriso->result_line, 1); strcat(xorriso->result_line, "\n"); Xorriso_result(xorriso, 0); return(1); } /* @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); } /* @param flag bit0=do not complain about non existent node bit1= do not try to find truncated name first */ int Xorriso_node_from_path(struct XorrisO *xorriso, IsoImage *volume, char *path, IsoNode **node, int flag) { int ret; char *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= 2; if(!(flag & 2)) ret= iso_image_path_to_node(volume, path_pt, node); if(ret == 2) 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 "); Text_shellsafe(path_pt, xorriso->info_text, 1); strcat(xorriso->info_text, " in loaded ISO image"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); } return(0); } return(1); } /* @param flag bit0=do not complain about non existent node bit1= do not try to find truncated name first */ int Xorriso_dir_from_path(struct XorrisO *xorriso, char *purpose, char *path, IsoDir **dir_node, int flag) { IsoImage *volume; IsoNode *node; int ret, is_dir= 0; ret= Xorriso_get_volume(xorriso, &volume, 0); if(ret<=0) return(ret); ret= Xorriso_node_from_path(xorriso, volume, path, &node, flag & 3); 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, "%s path does not lead to a directory in ISO image", purpose); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } *dir_node= (IsoDir *) node; 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); } 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); }