libisoburn/xorriso/iso_manip.c

4463 lines
138 KiB
C
Raw Normal View History

/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
2015-05-14 11:40:13 +00:00
Copyright 2007-2015 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"
/* @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;
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(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 objetc.
@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;
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)
return(ret);
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))) {
ret= lstat(disk_path, &stbuf);
if(ret!=-