libisoburn/xorriso/iso_manip.c

4591 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;<