libisoburn/xorriso/iso_manip.c

4615 lines
142 KiB
C

/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2022 Thomas Schmitt, <scdbackup@gmx.net>
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 <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include "xorriso.h"
#include "xorriso_private.h"
#include "xorrisoburn.h"
#include "lib_mgt.h"
#include "iso_img.h"
#include "iso_tree.h"
#include "iso_img.h"
#include "iso_manip.h"
#include "sort_cmp.h"
#include "parse_exec.h"
#include "write_run.h"
#include "disk_ops.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)
bit3= with bit0: pretend to have indeed a directory
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) && ((flag & 8) || 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;
}
/* Preserve namespace isofs, but not ACL or system xattr */
ret= iso_node_set_attrs(node, num_attrs, names, value_lengths, values,
1 | 8 | 16);
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= NULL;
struct stat stbuf;
Xorriso_alloc_meM(part_name, char, SfileadrL);
ret= iso_image_add_new_dir(volume, dir, img_name, &new_dir);
if(ret < 0)
goto ex;
*node= (IsoNode *) new_dir;
if(lstat(disk_path, &stbuf) != -1)
Xorriso_transfer_properties(xorriso, &stbuf, disk_path, *node, 1 | 8);
if(xorriso->update_flags & 1) {
ret= Xorriso_mark_update_merge(xorriso, img_name, node, 1);
if(ret <= 0)
{ret= 0; goto ex;}
}
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)
goto ex;
}
sprintf(xorriso->info_text, "Split into %d parts: ", total_parts);
Text_shellsafe(nominal_target, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= 1;
ex:;
Xorriso_free_meM(part_name);
return(ret);
}
/*
@param flag bit0= ISO_NODE_NAME_NOT_UNIQUE exception mode:
Do not issue message. Return existing node into *node.
bit1= if name truncation happens: copy truncated into img_name
bit3= cut_out_node: offset and size are valid
bit8= hide in iso_rr
bit9= hide in joliet
bit10= hide in hfsplus
*/
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 *namept, *eff_name, *trunc_name= NULL;
off_t size= 0;
eff_name= img_name;
if(lstat(disk_path, &stbuf) != -1) {
stbuf_valid= 1;
if(S_ISREG(stbuf.st_mode))
size= stbuf.st_size;
}
if((int) strlen(eff_name) > xorriso->file_name_limit) {
Xorriso_alloc_meM(trunc_name, char, SfileadrL);
strncpy(trunc_name, eff_name, SfileadrL - 1);
trunc_name[SfileadrL - 1]= 0;
ret= iso_truncate_leaf_name(1, xorriso->file_name_limit, trunc_name, 0);
if(ret < 0)
goto ex;
strcpy(xorriso->info_text, "File name had to be truncated and MD5 marked: ");
Text_shellsafe(eff_name, xorriso->info_text, 1);
strcat(xorriso->info_text, " -> ");
Text_shellsafe(trunc_name, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
eff_name= trunc_name;
if(flag & 2)
strcpy(img_name, trunc_name);
}
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 ",
(double) xorriso->file_size_limit, (double) cut_size);
Text_shellsafe(disk_path, xorriso->info_text, 1);
strcat(xorriso->info_text, "\n");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
ret= iso_tree_add_new_cut_out_node(volume, dir, eff_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, eff_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: ",
(double) xorriso->file_size_limit);
Text_shellsafe(disk_path, xorriso->info_text, 1);
strcat(xorriso->info_text, "\n");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
} else {
ret= iso_tree_add_new_node(volume, dir, eff_name, disk_path, node);
if(ret<0)
goto ex;
}
}
if(flag & (256 | 512 | 1024)) {
ret= Xorriso_set_hidden(xorriso, (void *) *node, "", (flag >> 8) & 7, 0);
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;
}
if(xorriso->update_flags & 1) {
ret= Xorriso_mark_update_merge(xorriso, eff_name, *node, 1);
if(ret <= 0)
goto ex;
}
ex:;
if(ret<0) {
if(ret == (int) ISO_NODE_NAME_NOT_UNIQUE && (flag & 1)) {
iso_image_dir_get_node(volume, dir, eff_name, node, 0);
} else {
Xorriso_process_msg_queues(xorriso,0);
if(ret == (int) ISO_RR_NAME_TOO_LONG ||
ret == (int) ISO_RR_NAME_RESERVED ||
ret == (int) ISO_RR_PATH_TOO_LONG)
namept= nominal_target;
else
namept= nominal_source;
Xorriso_report_iso_error(xorriso, namept, ret,
"Cannot add node to tree", 0, "FAILURE", 1|2);
}
} else {
if(LIBISO_ISREG(*node))
xorriso->pacifier_byte_count+= iso_file_get_size((IsoFile *) *node);
ret= 1;
}
Xorriso_free_meM(trunc_name);
return(ret);
}
/*
@param boss_iter Opaque handle to be forwarded to actions in ISO image
Set to NULL if calling this function without having
a boss iterator object.
@param node Pointer to pointer to existing node,
*node is set to NULL, if the node gets removed.
@param flag bit0= source is directory
bit4= return 3 on rejection by exclusion or user
bit6= do not delete eventually existing node from di_array
bit7= no special handling of split file directories
@return 1= no action was needed, 2= target removed,
3= rejected with bit4, <=0 means error
*/
int Xoriso_handle_collision(struct XorrisO *xorriso, void *boss_iter,
IsoNode **node, char *img_path,
char *full_img_path, char *disk_path,
char *show_path, int flag)
{
int ret, target_is_dir, target_is_split, source_is_dir;
source_is_dir= flag & 1;
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, img_path,
1 | 8 | (flag & 64));
if(ret <= 0)
return(ret);
if(ret == 3) {
sprintf(xorriso->info_text, "User revoked adding of: ");
Text_shellsafe(show_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(3 * !!(flag & 16));
}
*node= NULL;
return(2);
}
if (disk_path[0])
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
if(strcmp(full_img_path, img_path) == 0)
sprintf(xorriso->info_text,
"While grafting '%s' : file object exists and may not be overwritten",
img_path);
else
sprintf(xorriso->info_text,
"While grafting '%s' : '%s' exists and may not be overwritten",
full_img_path, img_path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
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
bit8= hide in iso_rr
bit9= hide in joliet
*/
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, source_is_dir, source_is_link, fret, was_failure= 0;
int do_not_dive, hide_attrs;
struct DirseQ *dirseq= NULL;
char *name, *img_name, *srcpt, *stbuf_src= "";
struct stat stbuf, hstbuf;
dev_t dir_dev;
struct LinkiteM *own_link_stack = NULL;
char *sfe= NULL, *sfe2= NULL;
char *disk_path= NULL, *img_path= NULL, *link_target= NULL;
#define Xorriso_add_handle_collisioN 1
#define Xorriso_optimistic_add_treE 1
#ifndef Xorriso_optimistic_add_treE
#ifndef Xorriso_add_handle_collisioN
int target_is_split= 0, target_is_dir;
#endif
#endif
/* 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] == 0)
strcat(img_path, "/");
else if(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;
/* Check for mkisofs-style hidings */
hide_attrs= (flag >> 8) & 3;
if(hide_attrs != 3) {
ret= Xorriso_path_is_hidden(xorriso, disk_path, 0);
if(ret<0)
goto ex;
if(ret>=0)
hide_attrs|= ret;
}
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;
}
#ifdef Xorriso_optimistic_add_treE
ret= Xorriso_tree_graft_node(xorriso, volume, dir, srcpt, img_name,
"", img_path, (off_t) 0, (off_t) 0,
&node, 1 | (hide_attrs << 8));
if(ret == (int) ISO_NODE_NAME_NOT_UNIQUE) {
ret= Xoriso_handle_collision(xorriso, NULL, &node, img_path, img_path,
srcpt, img_path,
(!!source_is_dir) | (flag & (64 | 128)));
if(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, (hide_attrs << 8));
if(ret <= 0)
node= NULL;
}
}
#else /* Xorriso_optimistic_add_treE */
/* does a node exist with this name ? */
node= NULL;
if(dir != NULL) {
ret= iso_image_get_dir_node(volume, dir, img_name, &node);
} else {
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, (hide_attrs << 8));
}
#endif /* Xorriso_optimistic_add_treE */
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
bit1= do not check and perform hidings
*/
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= NULL, *ni= NULL, *nfd= NULL, *cpt;
struct stat stbuf;
Xorriso_alloc_meM(nfi, char, SfileadrL);
Xorriso_alloc_meM(ni, char, SfileadrL);
Xorriso_alloc_meM(nfd, char, SfileadrL);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, full_img_path, nfi,
1|2);
if(ret<=0)
goto ex;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, img_path, ni, 1|2);
if(ret<=0)
goto ex;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, full_disk_path, nfd,
1|2|4);
if(ret<=0)
goto ex;
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)
{ret= -1; goto ex;}
if(d>nfdc)
{ret= 0; goto ex;}
for(i= 0; i<d; i++) {
cpt= strrchr(nfd, '/');
if(cpt==NULL)
{ret= -1; goto ex;} /* should not happen */
*cpt= 0;
}
if(nfd[0]==0)
strcpy(nfd, "/");
if(stat(nfd, &stbuf)==-1)
{ret= 0; goto ex;}
Xorriso_transfer_properties(xorriso, &stbuf, nfd, (IsoNode *) dir,
((8 | 1) * ((flag&1) && d==0)) | 4 | 32);
sprintf(xorriso->info_text, "Copied properties for ");
Text_shellsafe(ni, xorriso->info_text, 1);
sprintf(xorriso->info_text+strlen(xorriso->info_text), " from ");
Text_shellsafe(nfd, xorriso->info_text, 1);
if(!((flag&1) && d==0))
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
if(!(flag & 2)) {
/* Check for mkisofs-style hidings */
ret= Xorriso_path_is_hidden(xorriso, nfd, 0);
if(ret<0)
goto ex;
if(ret>=0) {
/* Hide dir */
ret= Xorriso_set_hidden(xorriso, (void *) dir, "", ret, 0);
if(ret <= 0)
goto ex;
}
}
ret= 1;
ex:
Xorriso_free_meM(nfi);
Xorriso_free_meM(ni);
Xorriso_free_meM(nfd);
return(ret);
}
/* @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);
}
int Xorriso_add_symlink(struct XorrisO *xorriso, IsoDir *parent,
char *link_target, char *leaf_name,
char *nominal_path, int flag)
{
int ret= 0;
IsoSymlink *link= NULL;
IsoImage *volume;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret <= 0)
return(ret);
ret= iso_image_add_new_symlink(volume, parent, leaf_name, link_target, &link);
Xorriso_process_msg_queues(xorriso,0);
if(ret < 0) {
Xorriso_report_iso_error(xorriso, nominal_path, ret,
"Cannot create symbolic link", 0, "FATAL", 1);
ret= 0;
}
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
@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
bit8= hide in iso_rr
bit9= hide in joliet
bit10= ln -s: graft in as symbolic link.
Link target is handed over in parameter disk_path.
@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= NULL, *apt, *npt, *cpt;
char *disk_path_pt, *resolved_disk_path= NULL;
IsoDir *dir= NULL, *hdir;
IsoNode *node;
int done= 0, is_dir= 0, l, ret, source_is_dir, resolve_link= 0;
int hide_attrs;
struct stat stbuf;
#define Xorriso_graft_handle_collisioN 1
#define Xorriso_optimistic_graft_iN 1
#ifndef Xorriso_optimistic_graft_iN
#ifndef Xorriso_graft_handle_collisioN
int target_is_split, target_is_dir;
#endif
#endif
Xorriso_alloc_meM(path, char, SfileadrL);
Xorriso_alloc_meM(resolved_disk_path, char, SfileadrL);
hide_attrs= (flag >> 8) & 3;
if (disk_path == NULL && !(flag & 1)) {
Xorriso_msgs_submit(xorriso, 0,
"Program error: Xorriso_graft_in(): disk_path == NULL && !(flag & 1)",
0, "ABORT", 0);
{ret= -1; goto ex;}
}
if (disk_path == NULL) {
disk_path= "";
} else {
ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&4));
if(ret<0)
goto ex;
if(ret>0)
{ret= 3*!!(flag&16); goto ex;}
/* Check for mkisofs-style hidings */
if(hide_attrs != 3) {
ret= Xorriso_path_is_hidden(xorriso, disk_path, 0);
if(ret<0)
goto ex;
if(ret>=0)
hide_attrs|= ret;
}
}
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) {
if(disk_path[0])
Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Unsupported relative addressing in iso_rr_path ");
Text_shellsafe(img_path, xorriso->info_text, 1);
if(disk_path[0]) {
strcat(xorriso->info_text, " (disk: ");
Text_shellsafe(disk_path, xorriso->info_text, 1);
strcat(xorriso->info_text, ")");
}
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
{ret= 0; goto ex;}
}
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
strncpy(path, img_path, SfileadrL - 1);
path[SfileadrL - 1]= 0;
apt= npt= path;
if(!(flag & (1 | 1024))) {
if(disk_path[0] == 0) {
Xorriso_msgs_submit(xorriso, 0, "/", 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"Will not graft-in the whole local filesystem by path '/'");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
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 ");
Text_shellsafe(disk_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
{ret= 0; goto ex;}
}
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 ");
Text_shellsafe(disk_path, xorriso->info_text, 1);
strcat(xorriso->info_text, " is not a directory. Target ");
Text_shellsafe(img_path, xorriso->info_text, 1);
strcat(xorriso->info_text, " would be.");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
}
}
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);
{ret= 0; goto ex;}
}
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);
#ifdef Xorriso_optimistic_graft_iN
/* Directories of the source path are likely to exist already as directory
in the image.
That will cause two lookups with optimistic, and only one with
pessimistic.
So optimism will pay off only with the leaf. I.e. if(done).
*/
if(source_is_dir) { /* eventually create directory */
ret= iso_image_dir_get_node(volume, dir, apt, &node, 0);
if(ret == 1) {
ret= Xoriso_handle_collision(xorriso, boss_iter, &node, path,
img_path, disk_path,
disk_path[0] ? disk_path : img_path,
(!!source_is_dir) | (flag & (16 | 64 | 128)));
if(ret <= 0 || ret == 3)
goto ex;
if(ret == 1 && node != NULL)
dir= (IsoDir *) node;
} else
node= NULL;
if(node == NULL) {
ret= iso_image_add_new_dir(volume, dir, apt, &hdir);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso,0);
if(disk_path[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);
{ret= 0; goto ex;}
}
if(xorriso->update_flags & 1) {
ret= Xorriso_mark_update_merge(xorriso, path, (IsoNode *) hdir, 1);
if(ret <= 0)
{ret= 0; goto ex;}
}
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[0] && !done) {
/* This not only copies disk directory properties
but also sets eventual hide_attrs */
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(flag & 1024) {
ret= Xorriso_add_symlink(xorriso, dir, disk_path, apt, img_path, 0);
if(ret <= 0)
goto ex;
Xorriso_set_change_pending(xorriso, 0);
} 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)
goto ex;
}
} else {
if(resolve_link) {
ret= Xorriso_resolve_link(xorriso, disk_path, resolved_disk_path, 0);
if(ret<=0)
goto ex;
disk_path_pt= resolved_disk_path;
} else
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, 1 | (flag & 8) | (hide_attrs << 8));
if(ret == (int) ISO_NODE_NAME_NOT_UNIQUE) {
ret= Xoriso_handle_collision(xorriso, boss_iter, &node, img_path,
img_path, disk_path,
disk_path[0] ? disk_path : img_path,
(flag & (16 | 64 | 128)));
if(ret <= 0 || ret == 3)
goto ex;
ret= Xorriso_tree_graft_node(xorriso, volume, dir, disk_path_pt, apt,
disk_path, img_path, offset, cut_size,
&node, (flag & 8) | (hide_attrs << 8));
}
if(ret<=0) {
sprintf(xorriso->info_text, "Grafting failed: ");
Text_shellsafe(img_path, xorriso->info_text, 1);
strcat(xorriso->info_text, " = ");
Text_shellsafe(disk_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);
/* <<< Why set the name once again ?
iso_image_set_node_name(volume, node, apt, 1);
*/
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= '/';
#else /* Xorriso_optimistic_graft_iN */
node= NULL;
ret= iso_image_dir_get_node(volume, dir, apt, &node, 0);
if(ret == 1) {
#ifdef Xorriso_graft_handle_collisioN
ret= Xoriso_handle_collision(xorriso, boss_iter, &node, path, img_path,
disk_path,
disk_path[0] ? disk_path : img_path,
(!!source_is_dir) | (flag & (16 | 64 | 128)));
if(ret <= 0 || ret == 3)
goto ex;
if(ret == 2)
goto handle_path_node;
#else /* Xorriso_graft_handle_collisioN */
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)
goto ex;
if(ret==3) {
sprintf(xorriso->info_text, "User revoked adding of: ");
if(disk_path[0])
Text_shellsafe(disk_path, xorriso->info_text, 1);
else
Text_shellsafe(img_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
{ret= 3*!!(flag&16); goto ex;}
}
node= NULL;
goto handle_path_node;
}
if (disk_path[0])
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);
{ret= 0; goto ex;}
}
#endif /* ! Xorriso_graft_handle_collisioN */
dir= (IsoDir *) node;
}
handle_path_node:;
if(node==NULL && source_is_dir) { /* make a directory */
ret= iso_image_add_new_dir(volume, dir, apt, &hdir);
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
if(disk_path[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);
{ret= 0; goto ex;}
}
if(xorriso->update_flags & 1) {
ret= Xorriso_mark_update_merge(xorriso, path, (IsoNode *) hdir, 1);
if(ret <= 0)
{ret= 0; goto ex;}
}
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[0] && !done)
/* This not only copies disk directory properties
but also sets eventual hide_attrs */
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(flag & 1024) {
ret= Xorriso_add_symlink(xorriso, dir, disk_path, apt, img_path, 0);
if(ret <= 0)
goto ex;
} 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)
goto ex;
}
} else {
if(resolve_link) {
ret= Xorriso_resolve_link(xorriso, disk_path, resolved_disk_path, 0);
if(ret<=0)
goto ex;
disk_path_pt= resolved_disk_path;
} else
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) | (hide_attrs << 8));
if(ret<=0) {
sprintf(xorriso->info_text, "Grafting failed: ");
Text_shellsafe(img_path, xorriso->info_text, 1);
strcat(xorriso->info_text, " = ");
Text_shellsafe(disk_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);
iso_image_set_node_name(volume, node, apt, 1);
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= '/';
#endif /* ! Xorriso_optimistic_graft_iN */
}
Xorriso_process_msg_queues(xorriso,0);
ret= 1+!!is_dir;
ex:;
Xorriso_free_meM(path);
Xorriso_free_meM(resolved_disk_path);
return(ret);
}
/* @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= NULL, *eff_dest= NULL;
off_t src_size;
struct stat stbuf;
Xorriso_alloc_meM(eff_source, char, SfileadrL);
Xorriso_alloc_meM(eff_dest, char, SfileadrL);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, disk_path, eff_source,
2 | 4);
if(ret<=0)
goto ex;
ret= Xorriso_path_is_excluded(xorriso, disk_path, !(flag&1));
if(ret!=0)
{ret= 0; goto ex;}
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 ");
Text_shellsafe(eff_source, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
{ret= 0; goto ex;}
}
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 ");
Text_shellsafe(eff_source, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0);
{ret= 0; goto ex;}
}
}
if(S_ISREG(stbuf.st_mode)) {
src_size= stbuf.st_size;
} else if(!(S_ISDIR(stbuf.st_mode) || S_ISLNK(stbuf.st_mode) ||
S_ISFIFO(stbuf.st_mode) || S_ISSOCK(stbuf.st_mode))) {
src_size= startbyte + bytecount;
ret= Xorriso_determine_capacity(xorriso, eff_source, &src_size, NULL, 1);
if(ret <= 0)
goto unsupported_type;
if(src_size <= 0) {
Xorriso_msgs_submit(xorriso, 0,
"-cut_out: Special file with addressable size range of 0 encountered",
0, "FAILURE", 0);
goto unsupported_type;
}
} else {
unsupported_type:;
Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0);
if(S_ISDIR(stbuf.st_mode) || S_ISLNK(stbuf.st_mode) ||
S_ISFIFO(stbuf.st_mode) || S_ISSOCK(stbuf.st_mode)) {
sprintf(xorriso->info_text,
"-cut_out: File type (%s) is not suitable for this command: ",
Ftypetxt(stbuf.st_mode, 0));
} else {
sprintf(xorriso->info_text,
"-cut_out: File (%s) does not support or permit random read access: ",
Ftypetxt(stbuf.st_mode, 0));
}
Text_shellsafe(eff_source, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
if(src_size < startbyte) {
Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0);
sprintf(xorriso->info_text,
"-cut_out: Byte offset %.f larger than addressable file size %.f : ",
(double) startbyte, (double) src_size);
Text_shellsafe(eff_source, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, iso_rr_path, eff_dest,
2);
if(ret<=0)
goto ex;
ret= Xorriso_graft_in(xorriso, NULL, eff_source, eff_dest,
startbyte, bytecount, 8);
ex:;
Xorriso_free_meM(eff_source);
Xorriso_free_meM(eff_dest);
return(ret);
}
/* @param flag bit0= do not produce info message on success
bit1= do not raise protest if directory already exists
@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= NULL;
Xorriso_alloc_meM(eff_path, char, SfileadrL);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 1);
if(ret<0)
{ret= -2; goto ex;}
if(ret>0) {
if(ret == 2 && (flag & 2))
{ret= 0; goto ex;}
sprintf(xorriso->info_text,"-mkdir: Address already existing ");
Text_shellsafe(eff_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0,
(ret==2 ? "WARNING" : "FAILURE"), 0);
{ret= -1 + (ret == 2); goto ex;}
}
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 2);
if(ret<0)
{ret= -2; goto ex;}
ret= Xorriso_graft_in(xorriso, NULL, NULL, eff_path, (off_t) 0, (off_t) 0, 1);
if(ret<=0)
{ret= -2; goto ex;}
if(!(flag&1)) {
sprintf(xorriso->info_text, "Created directory in ISO image: ");
Text_shellsafe(eff_path, xorriso->info_text, 1);
strcat(xorriso->info_text, "\n");
Xorriso_info(xorriso, 0);
}
ret= 1;
ex:;
Xorriso_free_meM(eff_path);
return(ret);
}
/* @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= NULL, *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) && !(flag & 1)) {
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) || ((void *) root_dir) == ((void *) victim_node)) {
/* 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(((void *) root_dir) == ((void *) victim_node))
{ret= 2; 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, (1u<<31));
return(ret);
}
int Xorriso_overwrite_dest(struct XorrisO *xorriso, void *boss_iter,
char *eff_dest, int dest_ret, char *activity,
int flag)
{
int ret;
if(dest_ret==2 && xorriso->do_overwrite!=1) {
sprintf(xorriso->info_text, "%s: May not overwrite directory: ", activity);
Text_shellsafe(eff_dest, xorriso->info_text, 1);
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, "%s: May not overwrite: ", activity);
Text_shellsafe(eff_dest, xorriso->info_text, 1);
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, "%s: User revoked removal of: ", activity);
Text_shellsafe(eff_dest, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
return(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= silently ignore attempt of renaming to same path
and return 2
*/
int Xorriso_rename(struct XorrisO *xorriso, void *boss_iter,
char *origin, char *dest, int flag)
{
int ret, ol, dest_ret;
char *eff_dest= NULL, *dir_adr= NULL, *cpt;
char *leafname, *eff_origin= NULL, *old_leafname;
IsoImage *volume;
IsoDir *origin_dir, *dest_dir;
IsoNode *node, *iso_node;
Xorriso_alloc_meM(eff_dest, char, SfileadrL);
Xorriso_alloc_meM(dir_adr, char, SfileadrL);
Xorriso_alloc_meM(eff_origin, char, SfileadrL);
#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 ");
Text_shellsafe(origin, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
{ret= -1; goto ex;}
}
#endif /* Libisofs_iso_dir_iter_sufficienT */
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, origin, eff_origin, 0);
if(ret<=0)
goto ex;
dest_ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest,1);
if(dest_ret<0)
{ret= dest_ret; goto ex;}
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)
goto ex;
}
/* 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);
{ret= 0; goto ex;}
} else if(strcmp(eff_origin, eff_dest)==0) {
if(flag & 1)
{ret= 2; goto ex;}
sprintf(xorriso->info_text, "Ignored attempt to rename ");
Text_shellsafe(eff_origin, xorriso->info_text, 1);
strcat(xorriso->info_text, " to itself");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
{ret= 0; goto ex;}
} else if(strncmp(eff_origin, eff_dest, ol)==0 &&
(eff_dest[ol]==0 || eff_dest[ol]=='/')) {
sprintf(xorriso->info_text, "May not rename ");
Text_shellsafe(eff_origin, xorriso->info_text, 1);
strcat(xorriso->info_text, " to its own sub address ");
Text_shellsafe(eff_dest, xorriso->info_text, 1 | 2);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
}
/* Check whether destination exists and may be not overwritable */
ret= Xorriso_overwrite_dest(xorriso, boss_iter,
eff_dest, dest_ret, "Renaming", 0);
if(ret <= 0)
goto ex;
/* 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)
goto ex;
}
/* Move node */
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
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);
{ret= -1; goto ex;}
}
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);
{ret= -1; goto ex;}
}
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_image_set_node_name(volume, node, leafname, 1);
else
ret= 1;
if(ret<0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, eff_dest, ret, "Cannot set name", 0,
"FAILURE", 1);
ret= iso_dir_add_node(origin_dir, node, 0);
Xorriso_process_msg_queues(xorriso,0);
if(ret < 0)
Xorriso_report_iso_error(xorriso, eff_origin, ret,
"Cannot re-instate node at old path",
0, "FAILURE", 1);
{ret= -1; goto ex;}
}
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);
{ret= -1; goto ex;}
}
Xorriso_set_change_pending(xorriso, 0);
ret= 1;
ex:;
Xorriso_free_meM(eff_dest);
Xorriso_free_meM(dir_adr);
Xorriso_free_meM(eff_origin);
return(ret);
}
int Xorriso_cannot_clone(struct XorrisO *xorriso, char *eff_origin,
char *eff_dest, int iso_error, int flag)
{
Xorriso_report_iso_error(xorriso, eff_dest, iso_error, "Cannot clone",
0, "FAILURE", 1);
sprintf(xorriso->info_text, "Failed to clone ");
Text_shellsafe(eff_origin, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
/* @param flag bit0= for iso_tree_clone() : merge directories
bit1= do not issue NOTE message
*/
int Xorriso_clone_tree(struct XorrisO *xorriso, void *boss_iter,
char *origin, char *dest, int flag)
{
int ret, dest_ret, l;
char *eff_dest= NULL, *eff_origin= NULL, *dir_adr= NULL;
char *leafname;
IsoImage *volume;
IsoDir *new_parent;
IsoNode *origin_node, *dir_node, *new_node;
Xorriso_alloc_meM(eff_dest, char, SfileadrL);
Xorriso_alloc_meM(eff_origin, char, SfileadrL);
Xorriso_alloc_meM(dir_adr, char, SfileadrL);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret <= 0)
goto ex;
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, origin, eff_origin, 0);
if(ret<=0)
goto ex;
ret= Xorriso_node_from_path(xorriso, volume, eff_origin, &origin_node, 0);
if(ret <= 0)
goto ex;
dest_ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest,1);
if(dest_ret<0)
{ret= dest_ret; goto ex;}
if(dest_ret > 0) {
if(eff_dest[0] == 0)
strcpy(eff_dest, "/");
sprintf(xorriso->info_text,
"Cloning: Copy address already exists: ");
Text_shellsafe(eff_dest, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
} else {
/* obtain eff_dest address despite it does not exist */
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest, 2);
if(ret<=0)
goto ex;
}
/* Obtain parent path and leaf name */
strcpy(dir_adr, eff_dest);
for(l= strlen(dir_adr); l > 0; ) {
if(dir_adr[l - 1] == '/')
dir_adr[--l]= 0;
else
break;
}
leafname= strrchr(dir_adr, '/');
if(leafname == NULL) {
leafname= dir_adr;
if (leafname[0] == 0) {
Xorriso_msgs_submit(xorriso, 0, "Empty file name as clone destination",
0, "FAILURE", 0);
{ret= 0; goto ex;}
}
} else {
*leafname= 0;
leafname++;
if(dir_adr[0] != 0) {
/* Ensure existence of destination directory */
ret= Xorriso_graft_in(xorriso, boss_iter, NULL, dir_adr,
(off_t) 0, (off_t) 0, 1);
if(ret <= 0)
goto ex;
}
}
ret= Xorriso_node_from_path(xorriso, volume, dir_adr, &dir_node, 0);
if(ret <= 0)
goto ex;
new_parent= (IsoDir *) dir_node;
ret = iso_image_tree_clone(volume, origin_node, new_parent, leafname,
&new_node, (flag & 1) | 2);
Xorriso_process_msg_queues(xorriso,0);
if(ret < 0) {
Xorriso_cannot_clone(xorriso, eff_origin, eff_dest, ret, 0);
{ret= 0; goto ex;}
}
Xorriso_set_change_pending(xorriso, 0);
if(!(flag & 2)) {
strcpy(xorriso->info_text, "Cloned in ISO image: ");
Text_shellsafe(eff_origin, xorriso->info_text, 1);
strcat(xorriso->info_text, " to ");
Text_shellsafe(eff_dest, xorriso->info_text, 1 | 2);
strcat(xorriso->info_text, "\n");
Xorriso_info(xorriso, 0);
}
ret= 1;
ex:;
Xorriso_free_meM(eff_dest);
Xorriso_free_meM(eff_origin);
Xorriso_free_meM(dir_adr);
return(ret);
}
int Xorriso_clone_under(struct XorrisO *xorriso, char *origin, char *dest,
int flag)
{
int ret, pass;
char *eff_dest= NULL, *eff_origin= NULL, *namept;
IsoDir *origin_dir, *dest_dir;
IsoDirIter *iter= NULL;
IsoNode *origin_node, *new_node;
IsoImage *volume;
Xorriso_alloc_meM(eff_dest, char, SfileadrL);
Xorriso_alloc_meM(eff_origin, char, SfileadrL);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret <= 0)
goto ex;
ret= Xorriso_dir_from_path(xorriso, "Copy source", origin, &origin_dir, 0);
if(ret <= 0)
goto ex;
ret= Xorriso_dir_from_path(xorriso, "Copy destination", dest, &dest_dir, 0);
if(ret <= 0)
goto ex;
for(pass= 0; pass < 2; pass++) {
ret= iso_dir_get_children(origin_dir, &iter);
if(ret < 0) {
Xorriso_cannot_create_iter(xorriso, ret, 0);
{ret= -1; goto ex;}
}
Xorriso_process_msg_queues(xorriso,0);
while(iso_dir_iter_next(iter, &origin_node) == 1) {
namept= (char *) iso_node_get_name(origin_node);
sprintf(eff_origin, "%s/%s", origin, namept);
sprintf(eff_dest, "%s/%s", dest, namept);
if(pass == 0) {
ret= Xorriso_node_from_path(xorriso, volume, eff_dest, &new_node, 1);
if(ret < 0)
goto ex;
if(ret > 0) {
sprintf(xorriso->info_text, "Cloning: Copy address already exists: ");
Text_shellsafe(eff_dest, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
} else {
ret = iso_image_tree_clone(volume, origin_node, dest_dir, namept,
&new_node, 1 | 2);
Xorriso_process_msg_queues(xorriso,0);
if(ret < 0) {
Xorriso_cannot_clone(xorriso, eff_origin, eff_dest, ret, 0);
ret= 0; goto ex;
}
}
}
iso_dir_iter_free(iter);
iter= NULL;
}
Xorriso_set_change_pending(xorriso, 0);
ret= 1;
ex:;
if(iter != NULL)
iso_dir_iter_free(iter);
Xorriso_free_meM(eff_dest);
Xorriso_free_meM(eff_origin);
Xorriso_process_msg_queues(xorriso,0);
return(ret);
}
int Xorriso_set_st_mode(struct XorrisO *xorriso, char *in_path,
mode_t mode_and, mode_t mode_or, int flag)
{
mode_t mode= 0;
int ret;
IsoNode *node;
char *path= NULL;
Xorriso_alloc_meM(path, char, SfileadrL);
ret= Xorriso_get_node_by_path(xorriso, in_path, path, &node, 0);
if(ret<=0)
goto ex;
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 ",
(unsigned int) (mode & 0xffff));
Text_shellsafe(path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
Xorriso_set_change_pending(xorriso, 0);
Xorriso_process_msg_queues(xorriso,0);
ret= 1;
ex:;
Xorriso_free_meM(path);
return(ret);
}
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, 4);
Xorriso_process_msg_queues(xorriso,0);
if(ret <= 0) {
Xorriso_report_iso_error(xorriso, "", ret,
"Error when setting ACL to image node",
0, "FAILURE", 1);
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:;
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 in_num_attrs, char **in_names,
size_t *in_value_lengths, char **in_values, int flag)
{
int ret, block_isofs= 0, in_original= 1;
size_t i, j, num_attrs;
IsoNode *node;
char **names, **values;
size_t *value_lengths;
num_attrs= in_num_attrs;
names= in_names;
value_lengths= in_value_lengths;
values= in_values;
node= (IsoNode *) in_node;
if(node == NULL) {
ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0);
if(ret<=0)
goto ex;
}
if((xorriso->do_aaip & 1024) && !(flag & 8)) {
flag|= 8;
block_isofs= 1;
for(i= 0; i < in_num_attrs; i++) {
if(strncmp(in_names[i], "isofs.", 6) == 0) {
if(in_original) {
strcpy(xorriso->info_text,
"Attempt to set xattr from namespace \"isofs\" to ");
Text_shellsafe(path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
ret= Xorriso_eval_problem_status(xorriso, 0, 0);
if(ret < 0) {
ret= 0; goto ex;
}
/* Switch to copy mode and omit isofs names */
Xorriso_alloc_meM(names, char *, num_attrs);
Xorriso_alloc_meM(value_lengths, size_t, num_attrs);
Xorriso_alloc_meM(values, char *, num_attrs);
in_original= 0;
for(j= 0; j < i; j++) {
names[j]= in_names[j];
value_lengths[j]= in_value_lengths[j];
values[j]= in_values[j];
}
num_attrs= i;
}
} else if(!in_original) {
names[num_attrs]= in_names[i];
value_lengths[num_attrs]= in_value_lengths[i];
values[num_attrs]= in_values[i];
num_attrs++;
}
}
}
if(num_attrs <= 0) {
ret= 1; goto ex;
}
ret= iso_node_set_attrs(node, num_attrs, names, value_lengths, values,
(flag & (1 | 2 | 4 | 8)) | (block_isofs << 4));
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);
if(!in_original) {
Xorriso_free_meM(names);
Xorriso_free_meM(value_lengths);
Xorriso_free_meM(values);
}
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 < (int) 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 < (int) 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 < (int) 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 < (int) 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;
Xorriso_alloc_meM(disk_path, char, SfileadrL);
/* Lookup all di_array instances of node */
if(LIBISO_ISDIR(node))
{ret= 3; goto ex;}
ret= Xorriso_search_di_range(xorriso, node, &idx, &low, &high, 2);
if(ret <= 0)
{ret= 3; goto ex;}
/* 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)
{ret= 3; goto ex;}
ret= Xorriso_pfx_disk_path(xorriso, abs_path, iso_prefix, disk_prefix,
disk_path, 0);
if(ret <= 0)
goto ex;
ret= Sfile_type(disk_path, 1);
if(ret < 0)
{ret= 3; goto ex;} /* does not exist on disk */
/* >>> compare_result bit17 = is_split */;
ret= Xorriso_update_interpreter(xorriso, boss_iter, NULL,
compare_result, disk_path, abs_path, 1);
if(ret <= 0)
goto ex;
ex:;
Xorriso_free_meM(disk_path);
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;
if(hide_state & 4)
hide_attrs|= LIBISO_HIDE_ON_HFSPLUS;
}
iso_node_set_hidden(node, hide_attrs);
return(1);
}
/* @param flag bit0= increase only upper estimation
*/
int Xorriso_estimate_file_size(struct XorrisO *xorriso, struct FindjoB *job,
char *basename, mode_t st_mode, off_t st_size, int flag)
{
off_t upper, lower, size;
lower = 3 * strlen(basename) + 34; /* >>> + minimum RR ? */
upper = 3 * strlen(basename) + 2048;
if(S_ISREG(st_mode)) {
size= ((st_size + (off_t) 2047) / (off_t) 2048) * (off_t) 2048;
lower+= size;
upper+= size;
} else if(S_ISDIR(st_mode)) {
upper+= 4096;
}
job->estim_upper_size+= upper;
if(!(flag & 1))
job->estim_lower_size+= lower;
return(1);
}
/* @param flag bit0= do not compare but print input and back converted name
*/
int Xorriso_test_outchar(struct XorrisO *xorriso, void *node_pt,
int name_space, int flag)
{
IsoNode *node;
char *result= NULL, *name, *back= NULL;
int ret, relax_mem;
size_t result_len, back_len, i;
struct isoburn_imgen_opts *sopts= NULL;
relax_mem= xorriso->relax_compliance;
node= (IsoNode *) node_pt;
ret= isoburn_igopt_new(&sopts, 0);
if(ret<=0) {
Xorriso_process_msg_queues(xorriso, 0);
ret= -1; goto ex;
}
if(!(flag & 1))
xorriso->relax_compliance|= isoburn_igopt_omit_version_numbers;
ret= Xorriso_make_iso_write_opts(xorriso, NULL, sopts, 0);
if(ret <= 0) {
ret= -1; goto ex;
}
if(iso_node_get_type(node) == LIBISO_DIR)
name_space |= 256;
name_space|= 512; /* no error messages */
name= (char *) iso_node_get_name(node);
if(name == NULL) {
ret= 1; goto ex;
}
ret= isoburn_conv_name_chars(sopts, name, strlen(name), &result, &result_len,
name_space);
if(ret <= 0) {
Xorriso_process_msg_queues(xorriso, 0);
if(flag & 1)
goto print_outname;
ret= 0; goto ex;
}
/* Convert back and compare with original */
ret= isoburn_conv_name_chars(sopts, result, result_len, &back, &back_len,
name_space | (1 << 15));
if(ret <= 0) {
Xorriso_process_msg_queues(xorriso, 0);
if(flag & 1)
goto print_outname;
ret= 0; goto ex;
}
if(flag & 1) {
print_outname:;
Text_shellsafe(name, xorriso->result_line, 0);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
if(back == NULL)
strcpy(xorriso->result_line, "(file name conversion error)");
else
Text_shellsafe(back, xorriso->result_line, 0);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
strcpy(xorriso->result_line, "--\n");
Xorriso_result(xorriso, 0);
} else {
for(i= 0; i < back_len; i++)
if(name[i] != back[i])
{ret= 0; goto ex;}
if(name[i] != 0)
{ret= 0; goto ex;}
}
ret= 1;
ex:;
isoburn_igopt_destroy(&sopts, 0);
if(result != NULL)
free(result);
if(back != NULL)
free(back);
xorriso->relax_compliance= relax_mem;
return(ret);
}
int Xorriso_set_to_mtime(struct XorrisO *xorriso, char *show_path,
IsoNode *node, int flag)
{
time_t t;
t= iso_node_get_mtime(node);
iso_node_set_atime(node, t);
iso_node_set_ctime(node, t);
Xorriso_set_change_pending(xorriso, 0);
return(1);
}
int Xorriso_cannot_create_iter(struct XorrisO *xorriso, int iso_error,int flag)
{
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", iso_error, "Cannot create iter", 0,
"FATAL", 1);
sprintf(xorriso->info_text, "Cannot create IsoDirIter object");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
return(1);
}
/* 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&(1u<<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|(1u<<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)
4=ok, end findjob gracefully
*/
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, i, bless_idx;
int unbless= 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, *iso_prefix, md5[16], *basename, bless_code[17];
char crtp[10];
struct FindjoB *subjob;
struct stat dir_stbuf, stbuf;
void *xinfo;
struct iso_hfsplus_xinfo_data *hfsplus_xinfo;
size_t value_length;
char *value;
action= Findjob_get_action_parms(job, &target, &text_2, &user, &group,
&mode_and, &mode_or, &type, &date, &subjob, 0);
if(action<0)
action= 0;
job->match_count++;
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 || action == 41) {
/* compare , update , update_merge */
Findjob_get_start_path(job, &iso_prefix, 0);
ret= Xorriso_find_compare(xorriso, (void *) boss_iter, (void *) node,
abs_path, iso_prefix, target,
(action == 17 || action == 41)
| ((flag&1)<<1) | ((action == 41) << 2));
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,
&job->last_data_file_block, 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 || action == 52) { /* show_stream , show_stream_id */
ret= Xorriso_show_stream(xorriso, (void *) node, show_path, (action == 52));
} 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);
Xorriso_set_change_pending(xorriso, 0);
} else if(action == 39) { /* hide */
Xorriso_set_hidden(xorriso, node, NULL, type, 0);
} else if(action == 40) { /* estimate_size */
basename= strrchr(abs_path, '/');
if(basename != NULL)
basename++;
else
basename= abs_path;
ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
if(ret > 0)
ret= Xorriso_estimate_file_size(xorriso, job, basename, stbuf.st_mode,
stbuf.st_size, 0);
} else if(action == 42) { /* rm_merge */
ret= Xorriso_mark_update_merge(xorriso, show_path, node, 2 | 4);
if(ret == 2) {
ret= Xorriso_rmi(xorriso, boss_iter, boss_mem, abs_path, 1|hflag);
sprintf(xorriso->info_text, "Deleted ");
Text_shellsafe(show_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0);
deleted= 1;
}
} else if(action == 43) { /* clear_merge */
ret= Xorriso_mark_update_merge(xorriso, show_path, node, 2 | 4);
} else if(action == 44) { /* list_extattr */
ret= Xorriso_list_extattr(xorriso, (void *) node, show_path, show_path,
target, 0);
} else if(action == 45) { /* set_hfs_crtp */
ret= Xorriso_hfsplus_file_creator_type(xorriso, show_path, (void *) node,
target, text_2, 0);
} else if(action == 46) { /* get_hfs_crtp */
ret= iso_node_get_xinfo(node, iso_hfsplus_xinfo_func, &xinfo);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso, 0);
ret= 0;
} else if(ret == 1) {
hfsplus_xinfo= (struct iso_hfsplus_xinfo_data *) xinfo;
for(i= 0; i < 4; i++)
xorriso->result_line[i]= hfsplus_xinfo->creator_code[i];
xorriso->result_line[4]= ' ';
for(i= 0; i < 4; i++)
xorriso->result_line[5 + i]= hfsplus_xinfo->type_code[i];
xorriso->result_line[9]= ' ';
xorriso->result_line[10]= 0;
Text_shellsafe(show_path, xorriso->result_line, 1);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
}
ret= 1;
} else if(action == 47) { /* set_hfs_bless */
if(strcmp(target, "none") == 0 ||
strcmp(target, "n") == 0 || strcmp(target, "N") == 0) {
ret= Xorriso_get_blessing(xorriso, node, &bless_idx, bless_code, 0);
if(ret < 0)
return(ret);
if(ret == 0)
return(1);
unbless= 1;
}
ret= Xorriso_hfsplus_bless(xorriso, show_path, (void *) node, target, 0);
/* If successful, end -find run gracefully */
if(ret > 0) {
if(unbless) {
sprintf(xorriso->info_text, "HFS blessing '%s' revoked from ",
bless_code);
} else {
sprintf(xorriso->info_text, "HFS blessing '%s' issued to ", target);
}
Text_shellsafe(show_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
}
if(!unbless)
return(4);
} else if(action == 48) { /* get_hfs_bless */
ret= Xorriso_get_blessing(xorriso, node, &bless_idx, bless_code, 0);
if (ret > 0) {
sprintf(xorriso->result_line, "%-16.16s ", bless_code);
Text_shellsafe(show_path, xorriso->result_line, 1);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
} else if(ret == 0)
ret= 1;
} else if(action == 49) {
/* internal: update creator, type, and blessings from persistent isofs.* */
ret= Xorriso_get_attr_value(xorriso, node, show_path, "isofs.hx",
&value_length, &value, 0);
if(ret < 0)
return(ret);
if(ret > 0) {
if(value_length >= 10) {
ret= Xorriso_hfsplus_file_creator_type(xorriso, show_path,
(void *) node,
value + 2, value + 6, 4);
} else
ret= 1;
free(value);
if(ret <= 0)
return(ret);
}
ret= Xorriso_get_attr_value(xorriso, node, show_path, "isofs.hb",
&value_length, &value, 0);
if(ret < 0)
return(ret);
if(ret > 0) {
if(value_length >= 1) {
bless_code[0]= value[0];
bless_code[1]= 0;
ret= Xorriso_hfsplus_bless(xorriso, show_path, (void *) node,
bless_code, 0);
} else
ret= 1;
free(value);
if(ret <= 0)
return(ret);
}
ret= 1;
} else if(action == 50) { /* print_outname */
ret= Xorriso_test_outchar(xorriso, (void *) node, type, 1);
if(ret <= 0)
return(ret);
} else if(action == 51) { /* report_sections */
ret= Xorriso_report_lba(xorriso, show_path, node,
&job->last_data_file_block, 1);
} else if(action == 53) { /* internal: show_hfs_cmd */
ret= Xorriso_get_blessing(xorriso, node, &bless_idx, bless_code, 0);
if (ret > 0) {
if(xorriso->show_hfs_cmd_flag & 2) {
sprintf(xorriso->result_line, "-hfs-bless-by %s ", bless_code);
Text_shellsafe(show_path, xorriso->result_line, 1);
} else {
sprintf(xorriso->result_line, "-find ");
Text_shellsafe(show_path, xorriso->result_line, 1);
sprintf(xorriso->result_line + strlen(xorriso->result_line),
" -exec set_hfs_bless %s --", bless_code);
}
ret= Xorriso_record_cmd_line(xorriso, xorriso->result_line,
xorriso->show_hfs_cmds,
&xorriso->show_hfs_cmd_count,
(xorriso->show_hfs_cmd_flag & 1));
if(ret <= 0)
return(ret);
}
ret= iso_node_get_xinfo(node, iso_hfsplus_xinfo_func, &xinfo);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso, 0);
ret= 0;
} else if(ret == 1) {
hfsplus_xinfo= (struct iso_hfsplus_xinfo_data *) xinfo;
for(i= 0; i < 4; i++)
crtp[i]= hfsplus_xinfo->creator_code[i];
crtp[4]= ' ';
for(i= 0; i < 4; i++)
crtp[5 + i]= hfsplus_xinfo->type_code[i];
crtp[9]= 0;
if(xorriso->show_hfs_cmd_flag & 2) {
sprintf(xorriso->result_line, "-hfsplus-file-creator-type %s ", crtp);
Text_shellsafe(show_path, xorriso->result_line, 1);
} else {
sprintf(xorriso->result_line, "-find ");
Text_shellsafe(show_path, xorriso->result_line, 1);
sprintf(xorriso->result_line + strlen(xorriso->result_line),
" -exec set_hfs_crtp %s --", crtp);
}
ret= Xorriso_record_cmd_line(xorriso, xorriso->result_line,
xorriso->show_hfs_cmds,
&xorriso->show_hfs_cmd_count,
(xorriso->show_hfs_cmd_flag & 1));
if(ret <= 0)
return(ret);
}
ret= 1;
} else if(action == 54 || action == 56) { /* internal: truncate_name */
ret= Xorriso_truncate_uniquely(xorriso, xorriso->file_name_limit,
node, abs_path, show_path,
2 * (action == 56));
} else if(action == 55 || action == 57) {
/* internal: unique_trunc_test length (in type) */
ret= Xorriso_truncate_uniquely(xorriso, type, node, abs_path, show_path,
1 | (2 * (action == 57)));
} else if(action == 58) { /* internal: last_data_file_block */
ret= Xorriso_report_lba(xorriso, show_path, node,
&job->last_data_file_block, 2);
} else if(action == 59) { /* set_to_mtime */
ret= Xorriso_set_to_mtime(xorriso, show_path, node, 0);
} else { /* includes : 15 in_iso */
Xorriso_esc_filepath(xorriso, show_path, xorriso->result_line, 0);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
ret= 1;
}
if(ret<=0)
return(ret);
if(deleted)
return(2);
if(no_dive)
return(3);
return(1);
}
/* flag bit0= perform -disk_path rather than -disk_name
bit0= use_pattern
*/
int Exprtest_match_disk_name(struct XorrisO *xorriso, struct ExprtesT *ftest,
IsoNode *node, int flag)
{
int ret;
char *disk_path= NULL, *npt;
regmatch_t name_match;
char *arg1;
void *arg2;
Xorriso_alloc_meM(disk_path, char, SfileadrL);
ret= Xorriso_retrieve_disk_path(xorriso, node, disk_path, 0);
if(ret <= 0)
{ret= 0; goto ex;}
if(flag & 1) {
if(strcmp(disk_path, ftest->arg1) == 0)
{ret= 1; goto ex;}
{ret= 0; goto ex;}
}
arg1= (char *) ftest->arg1;
arg2= ftest->arg2;
npt= strrchr(disk_path, '/');
if(npt != NULL)
npt++;
else
npt= disk_path;
if(flag & 2) {
ret= ! regexec(arg2, npt, 1, &name_match, 0);
} else {
ret= (strcmp(arg1, npt) == 0);
}
ex:;
Xorriso_free_meM(disk_path);
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, bless_idx, size_mode;
int lba_count, *file_end_lbas= NULL, *file_start_lbas= NULL, i, mask;
void *arg1, *arg2;
char ft, *decision, md5[16], bless_code[17];
regmatch_t name_match;
off_t damage_start, damage_end, size, *section_sizes= NULL, size_arg;
void *xinfo_dummy;
IsoNode *node;
IsoStream *stream;
struct iso_hfsplus_xinfo_data *hfsplus_xinfo;
if(ftest == NULL)
return(1);
node= (IsoNode *) node_pt;
arg1= ftest->arg1;
arg2= ftest->arg2;
if(node == NULL) {
switch(ftest->test_type) {
case 0: case 1: case 2: case 4: case 11: case 12: case 13:
case 22: case 23: case 25: case 26:
/* Tests which need no node parameter */
break;
default:
value= 0;
goto ex;
}
}
switch(ftest->test_type) {
case 0: /* -false */
value= 0;
break; case 1: /* -name *arg1 (regex in *arg2) */
if (ftest->boss->use_pattern) {
ret= regexec(arg2, name, 1, &name_match, 0);
value= !ret;
} else {
value= (strcmp((char *) arg1, name) == 0);
}
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, &section_sizes, &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) */
if (ftest->boss->use_pattern) {
ret= regexec(arg2, path, 1, &name_match, 0);
value= !ret;
} else {
value= (strcmp(arg1, path) == 0);
}
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,
2 * (ftest->boss->use_pattern));
break; case 17: /* -hidden int *arg1 */
value= 1;
ret= iso_node_get_hidden(node);
mask= *((int *) arg1) & 3;
if((!!(mask & 1)) ^ (!!(ret & LIBISO_HIDE_ON_RR)))
value= 0;
if((!!(mask & 2)) ^ (!!(ret & LIBISO_HIDE_ON_JOLIET)))
value= 0;
if((!!(mask & 3)) ^ (!!(ret & LIBISO_HIDE_ON_HFSPLUS)))
value= 0;
break; case 18: /* -has_hfs_crtp char *creator char *type */
ret= iso_node_get_xinfo(node, iso_hfsplus_xinfo_func, &xinfo_dummy);
value= 0;
if(ret < 0) {
Xorriso_process_msg_queues(xorriso, 0);
ret= 0;
} else if(ret == 1) {
hfsplus_xinfo= (struct iso_hfsplus_xinfo_data *) xinfo_dummy;
if((strlen(arg1) == 1 ||
(strncmp(arg1, (char *) hfsplus_xinfo->creator_code, 4) == 0 &&
strlen(arg1) == 4)) &&
(strlen(arg2) == 1 ||
(strncmp(arg2, (char *) hfsplus_xinfo->type_code, 4) == 0 &&
strlen(arg2) == 4)))
value= 1;
}
break; case 19: /* -has_hfs_bless int bless_index */
value= 0;
ret= Xorriso_get_blessing(xorriso, node, &bless_idx, bless_code, 0);
if (ret > 0) {
if(*((int *) arg1) == (int) ISO_HFSPLUS_BLESS_MAX ||
*((int *) arg1) == bless_idx)
value= 1;
}
break; case 20: /* -disk_path */
value= !! Exprtest_match_disk_name(xorriso, ftest, node,
1 | 2 * (ftest->boss->use_pattern));
break; case 21: /* -bad_outname */
ret= Xorriso_test_outchar(xorriso, node, *((int *) arg1), 0);
if(ret < 0) {
value= -1;
goto ex;
}
value= !ret; /* Xorriso_test_outchar() returns 1 for good and 0 for bad */
break; case 22: /* -use_pattern */
ftest->boss->use_pattern= (strcmp(arg1, "off") != 0);
value= 1;
break; case 23: /* -or_use_pattern */
ftest->boss->use_pattern= (strcmp(arg1, "off") != 0);
value= 0;
break; case 24: /* -name_limit_blocker */
ret= Xorriso_truncate_uniquely(xorriso, *((int *) arg1), node, path, path,
1 | 4);
value= (ret == 0);
break; case 25: /* -maxdepth */
value= (ftest->boss->depth <= *((int *) arg1));
break; case 26: /* -mindepth */
value= (ftest->boss->depth >= *((int *) arg1));
break; case 27: /* -size */
size_arg= *((off_t *) arg1);
size_mode= *((int *) arg2);
ret= Xorriso__get_file_size(node, &size, 0);
if(ret <= 0) {
if(ret < 0)
Xorriso_process_msg_queues(xorriso, 0);
value= 0;
goto ex;
}
if(size_mode == 0) {
value= (size == size_arg);
} else if(size_mode == 1) {
value= (size > size_arg);
} else if(size_mode == 2) {
value= (size >= size_arg);
} else if(size_mode == -1) {
value= (size < size_arg);
} else if(size_mode == -2) {
value= (size <= size_arg);
} else {
value= 0;
}
break; default:
/* >>> complain about unknown test type */;
value= -1;
}
ex:;
if(ftest->invert && value<=1 && value>=0)
value= !value;
if(file_start_lbas != NULL)
free((char *) file_start_lbas);
if(file_end_lbas != NULL)
free((char *) file_end_lbas);
if(section_sizes != NULL)
free((char *) section_sizes);
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 || action == 51) { /* report_lba, report_sections */
sprintf(xorriso->result_line,
"Report layout: %2s , %8s , %8s , %8s , %s\n",
"xt", "Startlba", "Blocks", action == 22 ? "Filesize" : "Sectsize",
"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
4= end gracefully
*/
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= 0, node_idx;
char *path= NULL, *abs_path= NULL;
job->depth= depth;
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);
job->last_data_file_block= 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(xorriso->request_to_abort)
{ret= 0; goto ex;}
if(ret == 4)
goto ex;
if(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 || action == 41 || action == 42)
hflag|= 2; /* need freedom to manipulate image */
if(action==14 || action==17 || action == 28 || action == 35 || action == 36 ||
action == 41)
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;
job->depth++;
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 == 4)
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;
if(xorriso->request_to_abort)
{ret= 0; goto ex;}
if(ret == 4)
goto ex;
}
}
ret= 1;
ex:;
job->depth= depth;
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, (1u<<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= NULL;
off_t mem_needed= 0;
array_job.start_path= NULL;
Xorriso_alloc_meM(abs_path, char, SfileadrL);
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;
if(ret == 4) /* end gracefully */
break;
}
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);
Xorriso_free_meM(abs_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) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
ret= -1; goto ex;
}
values= calloc(num_attr, sizeof(char *));
if(values== NULL) {
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);
}
int Xorriso__mark_update_xinfo(void *data, int flag)
{
/* data is an int disguised as pointer. It does not point to memory. */
return(1);
}
int Xorriso__mark_update_cloner(void *old_data, void **new_data, int flag)
{
*new_data= NULL;
if(flag)
return(ISO_XINFO_NO_CLONE);
if(old_data == NULL)
return(0);
/* data is an int disguised as pointer. It does not point to memory. */
*new_data= old_data;
return(0);
}
/* @param flag bit0= found on disk
bit1= inquire visit-found status:
1=not visited, 2=not found, 3=found
bit2= with bit1: delete xinfo before returning status
*/
int Xorriso_mark_update_merge(struct XorrisO *xorriso, char *path,
void *in_node, int flag)
{
int ret;
void *xipt= NULL;
IsoNode *node;
if(in_node == NULL) {
ret= Xorriso_node_from_path(xorriso, NULL, path, &node, 0);
if(ret <= 0)
return(ret);
} else
node= (IsoNode *) in_node;
ret= iso_node_get_xinfo(node, Xorriso__mark_update_xinfo, &xipt);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", ret,
"Error when looking for update_merge xinfo",
0, "FAILURE", 1);
return(0);
}
if(flag & 2) { /* Inquire status and optionally delete xinfo */
if(ret == 0)
return(1);
if(flag & 4) {
ret= iso_node_remove_xinfo(node, Xorriso__mark_update_xinfo);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", ret,
"Error when removing update_merge xinfo",
0, "FAILURE", 1);
return(0);
}
}
if(((char *) &xipt)[0])
return(3);
return(2);
}
/* xipt is a byte value disguised as void pointer */
if(ret == 1) {
if(((char *) &xipt)[0])
return(1);
if(!(flag & 1))
return(1);
} else
((char *) &xipt)[0]= 0;
if(flag & 1)
((char *) &xipt)[0]= 1;
ret= iso_node_remove_xinfo(node, Xorriso__mark_update_xinfo);
if(ret < 0)
goto set_error;
ret= iso_node_add_xinfo(node, Xorriso__mark_update_xinfo, xipt);
if(ret <= 0) {
set_error:;
Xorriso_process_msg_queues(xorriso,0);
Xorriso_report_iso_error(xorriso, "", ret,
"Error when trying to set update_merge xinfo",
0, "FAILURE", 1);
return(0);
}
return(1);
}
/* flag bit0= in case of error talk of "overwrite" rather than "remove"
*/
static int Xorriso_remove_hfsplus_crtp(struct XorrisO *xorriso, IsoNode *node,
char *path, int flag)
{
int ret;
char *msg, buf[10], *bufpt;
size_t l;
static char *name= "isofs.hx";
ret= iso_node_remove_xinfo(node, iso_hfsplus_xinfo_func);
Xorriso_process_msg_queues(xorriso, 0);
if(ret < 0) {
if(flag & 1)
msg= "Cannot overwrite HFS+ creator and type of ISO node";
else
msg= "Cannot remove HFS+ creator and type of ISO node";
Xorriso_report_iso_error(xorriso, path, ret, msg, 0, "FAILURE", 1);
return(0);
}
/* Delete isofs.hx attribute */
bufpt= buf;
/* >>> ??? check whether there is isofs.hx attached ? */;
ret= Xorriso_setfattr(xorriso, node, path,
(size_t) 1, &name, &l, &bufpt, 4 | 8);
return(ret);
}
static int Xorriso_set_hfsplus_crtp(struct XorrisO *xorriso, IsoNode *node,
char *path, char *creator, char *hfs_type,
int flag)
{
struct iso_hfsplus_xinfo_data *hfs_data= NULL;
char buf[10], *bufpt;
size_t l;
int ret;
static char *name= "isofs.hx";
/* Register as non-persistent xinfo */
hfs_data= iso_hfsplus_xinfo_new(0);
if(hfs_data == NULL) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
return(-1);
}
memcpy(hfs_data->creator_code, creator, 4);
memcpy(hfs_data->type_code, hfs_type, 4);
ret= iso_node_add_xinfo(node, iso_hfsplus_xinfo_func, (void *) hfs_data);
Xorriso_process_msg_queues(xorriso, 0);
if(ret < 0) {
Xorriso_report_iso_error(xorriso, path, ret,
"Cannot attach HFS+ creator and type to ISO node", 0, "FAILURE", 1);
goto failure;
} else if(ret == 0) {
strcat(xorriso->info_text,
"Program error: iso_node_add_xinfo refuses to attach HFS+ creator and type");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
goto failure;
}
/* Register as persistent attribute isofs.hx */
bufpt= buf;
l= 10;
buf[0]= 1;
buf[1]= 0;
memcpy(buf + 2, creator, 4);
memcpy(buf + 6, hfs_type, 4);
ret= Xorriso_setfattr(xorriso, node, path,
(size_t) 1, &name, &l, &bufpt, 2 | 8);
if(ret <= 0)
goto failure;
Xorriso_set_change_pending(xorriso, 0);
return(1);
failure:
if(hfs_data != NULL)
iso_hfsplus_xinfo_func(hfs_data, 1);
return(0);
}
/* @param flag bit0= only check creator and hfs_type for compliance.
bit1= with bit0: check for search rather than for setting
bit2= copy 2 times 4 bytes without any check
*/
int Xorriso_hfsplus_file_creator_type(struct XorrisO *xorriso, char *path,
void *in_node,
char *creator, char *hfs_type, int flag)
{
int ret;
IsoNode *node;
if(in_node == NULL && !(flag & 1)) {
ret= Xorriso_node_from_path(xorriso, NULL, path, &node, 0);
if(ret <= 0)
return(ret);
} else
node= (IsoNode *) in_node;
if(flag & 4) {
;
} else if((creator[0] == 0 && hfs_type[0] == 0) ||
strcmp(creator, "--delete") == 0) {
if(flag & 2) {
strcpy(xorriso->info_text,
"Attempt to use HFS+ file pseudo-creator '--delete' for searching");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
strcpy(xorriso->info_text,
"Suitable are strings of length 4 or length 1");
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
return(0);
}
if(flag & 1)
return(1);
ret= Xorriso_remove_hfsplus_crtp(xorriso, node, path, 0);
if(ret < 0)
return(ret);
return(1);
} else if((strlen(creator) != 4 && !(strlen(creator) == 1 &&
(flag & 3) == 3)) ||
(strlen(hfs_type) != 4 && !(strlen(hfs_type) == 1 &&
(flag & 3) == 3))) {
if(flag & 2) {
strcpy(xorriso->info_text,
"HFS+ file creator code or type code for searching are not exactly 1 or 4 characters long");
} else {
strcpy(xorriso->info_text,
"HFS+ file creator code or type code are not exactly 4 characters long");
}
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
if(flag & 1)
return(1);
ret= Xorriso_remove_hfsplus_crtp(xorriso, node, path, 1);
if(ret <= 0)
return(ret);
ret= Xorriso_set_hfsplus_crtp(xorriso, node, path, creator, hfs_type, 0);
if(ret <= 0)
return(ret);
return(1);
}
/*
@param node
If node is NULL and path is empty, then the blessing will be
revoked from any node which bears it.
@param flag
Bitfield for control purposes.
bit0= Revoke blessing if node != NULL bears it.
bit1= Revoke any blessing of the node, regardless of parameter
blessing. If node is NULL, then revoke all blessings.
bit2= Only check parameter blessing.
Return blessing index + 1 instead of issuing the blessing.
bit3= With bit2:
Allow blessing "any" and map to index ISO_HFSPLUS_BLESS_MAX.
Elsewise, blessing "none" is mapped to ISO_HFSPLUS_BLESS_MAX.
*/
int Xorriso_hfsplus_bless(struct XorrisO *xorriso, char *path,
void *in_node, char *blessing, int flag)
{
int ret, bless_max;
IsoNode *node, **blessed_nodes;
IsoImage *volume= NULL;
enum IsoHfsplusBlessings bless_code = ISO_HFSPLUS_BLESS_MAX; /* = invalid */
char *hb = "";
size_t l= 0;
static char *name= "isofs.hb";
if(strcmp(blessing, "ppc_bootdir") == 0 ||
strcmp(blessing, "p") == 0 || strcmp(blessing, "P") == 0) {
bless_code= ISO_HFSPLUS_BLESS_PPC_BOOTDIR;
hb= "p";
} else if(strcmp(blessing, "intel_bootfile") == 0 ||
strcmp(blessing, "i") == 0 || strcmp(blessing, "I") == 0) {
bless_code= ISO_HFSPLUS_BLESS_INTEL_BOOTFILE;
hb= "i";
} else if(strcmp(blessing, "show_folder") == 0 ||
strcmp(blessing, "s") == 0 || strcmp(blessing, "S") == 0) {
bless_code= ISO_HFSPLUS_BLESS_SHOWFOLDER;
hb= "s";
} else if(strcmp(blessing, "os9_folder") == 0 ||
strcmp(blessing, "9") == 0) {
bless_code= ISO_HFSPLUS_BLESS_OS9_FOLDER;
hb= "9";
} else if(strcmp(blessing, "osx_folder") == 0 ||
strcmp(blessing, "x") == 0 || strcmp(blessing, "X") == 0) {
bless_code= ISO_HFSPLUS_BLESS_OSX_FOLDER;
hb= "x";
} else if((!(flag & 8)) && (strcmp(blessing, "none") == 0 ||
strcmp(blessing, "n") == 0 || strcmp(blessing, "N") == 0)) {
bless_code= ISO_HFSPLUS_BLESS_MAX;
flag |= 2;
} else if((flag & 8) && (flag & 4) &&
(strcmp(blessing, "any") == 0 ||
strcmp(blessing, "a") == 0 || strcmp(blessing, "A") == 0)) {
bless_code= ISO_HFSPLUS_BLESS_MAX;
} else {
sprintf(xorriso->info_text, "Unknown blessing type ");
Text_shellsafe(blessing, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
}
if(flag & 4)
return(1 + bless_code);
if(in_node == NULL && path[0]) {
ret= Xorriso_node_from_path(xorriso, NULL, path, &node, 0);
if(ret <= 0)
return(ret);
} else
node= (IsoNode *) in_node;
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret <= 0)
return(ret);
if(!(flag & 2)) {
/* Remove persistent bless mark from current bearer */
ret= iso_image_hfsplus_get_blessed(volume, &blessed_nodes, &bless_max, 0);
Xorriso_process_msg_queues(xorriso, 0);
if(ret < 0) {
Xorriso_report_iso_error(xorriso, "", ret,
"Error when trying to bless a file",
0, "FAILURE", 1);
return(0);
}
if((int) bless_code < bless_max) {
if(blessed_nodes[(int) bless_code] != NULL) {
ret= Xorriso_setfattr(xorriso, blessed_nodes[(int) bless_code], "",
(size_t) 1, &name, &l, &hb, 4 | 8);
if(ret <= 0)
return(ret);
}
}
}
/* Bless node */
ret= iso_image_hfsplus_bless(volume, bless_code, node, flag & 3);
Xorriso_process_msg_queues(xorriso, 0);
if(ret == 0 && path[0]) {
if((flag & 3)) {
sprintf(xorriso->info_text,
"Attempt to revoke blessing of unblessed file");
} else {
sprintf(xorriso->info_text,
"Multiple blessing to same file or inappropriate file type");
}
if(path[0]) {
strcat(xorriso->info_text, ": ");
Text_shellsafe(path, xorriso->info_text, 1);
}
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
return(0);
} else if (ret < 0) {
Xorriso_report_iso_error(xorriso, "", ret,
"Error when trying to bless a file",
0, "FAILURE", 1);
return(0);
}
/* Attach persistent AAIP bless mark to node */
if(!(flag & 3)) {
l= 1;
ret= Xorriso_setfattr(xorriso, node, path, (size_t) 1, &name, &l, &hb,
2 | 8);
if(ret <= 0)
return(ret);
}
Xorriso_set_change_pending(xorriso, 0);
return(1);
}
int Xorriso_get_blessing(struct XorrisO *xorriso, IsoNode *node,
int *bless_idx, char bless_code[17], int flag)
{
IsoNode **blessed_nodes;
int bless_max, ret, i;
if(xorriso->in_volset_handle == NULL)
return(0);
ret= iso_image_hfsplus_get_blessed((IsoImage *) xorriso->in_volset_handle,
&blessed_nodes, &bless_max, 0);
Xorriso_process_msg_queues(xorriso, 0);
if(ret < 0) {
Xorriso_report_iso_error(xorriso, "", ret,
"Error when trying to inquire HFS+ file blessings",
0, "FAILURE", 1);
return(-1);
}
for(i= 0; i < bless_max; i++) {
if(blessed_nodes[i] == node) {
switch (i) {
case ISO_HFSPLUS_BLESS_PPC_BOOTDIR:
strcpy(bless_code, "ppc_bootdir");
break; case ISO_HFSPLUS_BLESS_INTEL_BOOTFILE:
strcpy(bless_code, "intel_bootfile");
break; case ISO_HFSPLUS_BLESS_SHOWFOLDER:
strcpy(bless_code, "show_folder");
break; case ISO_HFSPLUS_BLESS_OS9_FOLDER:
strcpy(bless_code, "os9_folder");
break; case ISO_HFSPLUS_BLESS_OSX_FOLDER:
strcpy(bless_code, "osx_folder");
break; default:
strcpy(bless_code, "unknown_blessing");
}
*bless_idx= i;
return(1);
}
}
return(0);
}
/* @param flag bit0= use file addresses as search patterns
*/
int Xorriso_apply_sort_file(struct XorrisO *xorriso, char *path, int flag)
{
int ret, linecount= 0, filec= 0, zero, i;
FILE *fp= NULL;
char *sret, *line= NULL, *spt, *tpt, *patterns[1], **filev= NULL;
char *sort_weight_args[4];
off_t mem= 0;
IsoImage *volume;
Xorriso_alloc_meM(line, char, SfileadrL);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
ret= Xorriso_afile_fopen(xorriso, path, "rb", &fp, 2);
if(ret <= 0)
{ret= 0; goto ex;}
while(1) {
sret= Sfile_fgets_n(line, SfileadrL - 1, fp, 0);
if(sret == NULL) {
if(ferror(fp))
{ret= 0; goto ex;}
break;
}
linecount++;
/* Find first space or tab */
spt= strchr(line, ' ');
tpt= strchr(line, '\t');
if(spt == NULL || (tpt != NULL && tpt < spt))
spt= tpt;
if(spt == NULL) {
sprintf(xorriso->info_text,
"No space or tab character found in line %d of sort weight file ",
linecount);
Text_shellsafe(path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
ret= 0; goto ex;
}
*spt= 0;
patterns[0]= spt + 1;
if(flag & 1) {
/* Obtain list of matching files */
ret= Xorriso_expand_pattern(xorriso, 1, patterns, 0,
&filec, &filev, &mem, 4);
if(ret <= 0)
{ret= 0; goto ex;}
} else {
filec= 1;
}
/* Apply weight to file or directory tree */
for(i= 0; i < filec; i++) {
zero= 0;
if(flag & 1) {
sort_weight_args[0]= filev[i];
} else {
sort_weight_args[0]= patterns[0];
}
sort_weight_args[1]= "-exec";
sort_weight_args[2]= "sort_weight";
sort_weight_args[3]= line;
ret= Xorriso_option_find(xorriso, 4, sort_weight_args, &zero, 2);
if(ret <= 0)
{ret= 0; goto ex;}
}
if(flag & 1)
Sfile_destroy_argv(&filec, &filev, 0);
}
ret= 1;
ex:
if(fp != NULL)
fclose(fp);
Xorriso_free_meM(line);
Sfile_destroy_argv(&filec, &filev, 0);
return(ret);
}
/* @param flag bit0= tolerate truncated files of old length
and mangle collisions
*/
int Xorriso_set_file_name_limit(struct XorrisO *xorriso, int value, int flag)
{
int ret;
IsoImage *volume= NULL;
struct FindjoB *job= NULL;
struct stat dir_stbuf;
ret= Xorriso_get_volume(xorriso, &volume, 1);
if(ret < 0)
goto ex;
if (ret == 1 && volume != NULL) {
/* Check whether there are non-refreshable truncated names */
ret= Findjob_new(&job, "/", 0);
if(ret<=0) {
Xorriso_no_findjob(xorriso, "xorriso", 0);
{ret= -1; goto ex;}
}
Findjob_set_action_type(job, 55 + 2 * (flag & 1), value, 0);
xorriso->find_unique_trunc_result= 2;
ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/",
&dir_stbuf, 0, 0);
if(ret < 0)
goto ex;
xorriso->request_to_abort= 0;
if(xorriso->find_unique_trunc_result == 0 && !(flag & 1)) {
Xorriso_msgs_submit(xorriso, 0,
"-file_name_limit may not be changed because truncated files exist or collisions would occur",
0, "SORRY", 0);
ret= 0; goto ex;
}
xorriso->file_name_limit= value;
iso_image_set_truncate_mode(volume, 1, value);
/* truncations are necessary */;
if(xorriso->find_unique_trunc_result == 1) {
Findjob_set_action_type(job, 54 + 2 * (flag & 1),
xorriso->file_name_limit, 0);
xorriso->find_unique_trunc_result= 2;
ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0, NULL, "/",
&dir_stbuf, 0, 0);
if(ret < 0)
goto ex;
if(xorriso->find_unique_trunc_result == 0) {
/* >>> Did not work . What to do ? */;
}
}
}
xorriso->file_name_limit= value;
ret= 1;
ex:;
Findjob_destroy(&job, 0);
return(ret);
}
/* @param flag bit0= test for uniqueness, do not change name
bit1= tolerate existing truncated names and mangle collisions
bit2= be silent about non-uniquely truncatables
do not set xorriso->request_to_abort
*/
int Xorriso_truncate_uniquely(struct XorrisO *xorriso, int length,
IsoNode *node, char *abs_path, char *show_path,
int flag)
{
int ret, l, i;
unsigned int mangleno;
char *name, *trunc= NULL, *old_name= NULL;
IsoDir *dir;
IsoNode *collider;
IsoImage *volume= NULL;
name= (char *) iso_node_get_name(node);
l= strlen(name);
/* Check for truncated name */
if(l == xorriso->file_name_limit && l != length && !(flag & 2)) {
i= 0;
if(name[l - 33] == ':') {
for(i= l - 32; i < l; i++)
if((name[i] < '0' || name[i] > '9') &&
(name[i] < 'a' || name[i] > 'f'))
break;
}
if(i == l) {
if(!(flag & 4)) {
sprintf(xorriso->info_text, "Truncated name of current limit found: ");
Text_shellsafe(name, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
}
xorriso->find_unique_trunc_result= 0;
{ret= 0; goto ex;}
}
}
/* Check for need to truncate */
if(l <= length)
{ret= 1; goto ex;}
if(xorriso->find_unique_trunc_result > 1)
xorriso->find_unique_trunc_result= 1;
trunc= strdup(name);
old_name= strdup(name);
if(trunc == NULL || old_name == NULL) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
ret= -1; goto ex;
}
ret= iso_truncate_leaf_name(1, length, trunc, 0);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso, 0);
Xorriso_report_iso_error(xorriso, "", ret,
"Error when truncating file name", 0, "SORRY", 1);
xorriso->find_unique_trunc_result= 0;
{ret= 0; goto ex;}
}
dir= iso_node_get_parent(node);
if(dir != NULL) {
/* (intentionally using deprecated call which does not truncate by itself)*/
ret= iso_dir_get_node(dir, trunc, &collider);
if(ret == 1) {
if((flag & 1) && !(flag & 2)) {
if(!(flag & 4)) {
sprintf(xorriso->info_text,
"Truncated name collides with existing name: ");
Text_shellsafe(name, xorriso->info_text, 1);
strcat(xorriso->info_text, " -> ");
Text_shellsafe(trunc, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
}
xorriso->find_unique_trunc_result= 0;
{ret= 0; goto ex;}
} else {
/* Mangle */
for(mangleno= 0; mangleno < 0xffffffff; mangleno++) {
Sfile_flatten_utf8_heads(trunc, length - 33 - 9, 0);
sprintf(trunc + length - 33 - 9, ":%-8.8X", mangleno);
trunc [length - 33] = ':';
ret= iso_dir_get_node(dir, trunc, &collider);
if(ret == 0)
break;
}
}
}
}
/* If only for testing: done now */
if(flag & 1)
{ret= 1; goto ex;}
if(xorriso->file_name_limit != length)
{ret= -1; goto ex;} /* Programming error */
ret= Xorriso_get_volume(xorriso, &volume, 1);
if(ret < 0)
{ret= -1; goto ex;} /* Programming error */
/* Set truncated name */
ret= iso_image_set_node_name(volume, node, trunc, 0);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso, 0);
xorriso->find_unique_trunc_result= 0;
{ret= 0; goto ex;}
}
Xorriso_set_change_pending(xorriso, 0);
sprintf(xorriso->info_text, "Truncated: ");
Text_shellsafe(old_name, xorriso->info_text, 1);
strcat(xorriso->info_text, " -> ");
Text_shellsafe(trunc, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
ret= 1;
ex:;
if(ret == 0 && (flag & 1) && !(flag & 4))
xorriso->request_to_abort= 1;
Xorriso_free_meM(old_name);
Xorriso_free_meM(trunc);
return(ret);
}