You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2539 lines
68 KiB

/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2012 Thomas Schmitt, <scdbackup@gmx.net>
Provided under GPL version 2 or later.
This file contains functions which access nodes of the
libisofs tree model.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include <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 <pwd.h>
#include <grp.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_manip.h"
#include "sort_cmp.h"
/* @param eff_path returns resulting effective path.
Must provide at least SfileadrL bytes of storage.
@param flag bit0= do not produce problem events (unless faulty path format)
bit1= work purely literally, do not use libisofs
bit2= (with bit1) this is an address in the disk world
bit3= return root directory as "/" and not as ""
bit4= (with bit2) determine type of disk file eff_path
and return 0 if not existing
bit5= (with bit3) this is not a parameter
bit6= insist in having an ISO image, even with bits1+2
@return -1 = faulty path format, 0 = not found ,
1 = found simple node , 2 = found directory
*/
int Xorriso_normalize_img_path(struct XorrisO *xorriso, char *wd,
char *img_path, char eff_path[], int flag)
{
int ret, is_dir= 0, done= 0;
IsoImage *volume;
IsoDir *dir= NULL;
IsoNode *node= NULL;
char *path= NULL, *apt, *npt, *cpt;
Xorriso_alloc_meM(path, char, SfileadrL);
if((flag&64) || !(flag&2)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
}
eff_path[0]= 0;
if(img_path[0]==0) {
if(flag&8)
strcpy(eff_path, "/");
{ret= 2; goto ex;} /* root directory */
}
apt= npt= path;
if(img_path[0]!='/') {
strcpy(path, wd);
ret= Sfile_add_to_path(path, img_path, 0);
if(ret<=0)
goto much_too_long;
} else
if(Sfile_str(path, img_path, 0)<=0)
{ret= -1; goto ex;}
if(path[0]!='/') {
sprintf(xorriso->info_text,
"Internal error: Unresolvable relative addressing in iso_rr_path '%s'",
img_path);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FATAL", 0);
{ret= -1; goto ex;}
} else if(path[1]==0) {
if(flag&8)
strcpy(eff_path, "/");
{ret= 2; goto ex;} /* root directory */
}
if(apt[0] == '.')
if(apt[1] == 0 || apt[1] == '/')
is_dir= 1;
for(npt= apt; !done; apt= npt+1) {
npt= strchr(apt, '/');
if(npt==NULL) {
npt= apt+strlen(apt);
done= 1;
} else
*npt= 0;
if(*apt==0) {
*apt= '/';
apt++;
if(done)
break;
continue;
}
if(strcmp(apt,".")==0)
continue;
if(strcmp(apt,"..")==0) {
if(!(flag&2)) {
node= (IsoNode *) dir;
if(node==NULL) {
bonked_root:;
sprintf(xorriso->info_text,
"Relative addressing in path exceeds root directory: ");
Text_shellsafe(img_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= -1; goto ex;}
}
dir= iso_node_get_parent(node);
}
/* truncate eff_path */;
cpt= strrchr(eff_path, '/');
if(cpt==NULL) /* ??? if not flag&2 then this is a bug */
goto bonked_root;
*cpt= 0;
is_dir= 1;
continue;
}
is_dir= 0;
ret= Sfile_add_to_path(eff_path, apt, 0);
if(ret<=0) {
much_too_long:;
sprintf(xorriso->info_text, "Effective path gets much too long (%d)",
(int) (strlen(eff_path)+strlen(apt)+1));
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= -1; goto ex;}
}
if(!(flag&2)) {
dir= (IsoDir *) node;
ret= Xorriso_node_from_path(xorriso, volume, eff_path, &node, flag&1);
if(ret<=0)
{ret= 0; goto ex;}
if(dir==NULL) /* could be false with "/dir/.." */
dir= iso_node_get_parent(node);
is_dir= LIBISO_ISDIR(node);
}
}
if(flag&16) {
ret= Sfile_type(eff_path,
1|(4*(xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&32)))
));
if(ret<0)
{ret= 0; goto ex;}
if(ret==2)
is_dir= 1;
else
is_dir= 0;
}
ret= 1+!!is_dir;
ex:;
Xorriso_free_meM(path);
return(ret);
}
int Xorriso_get_node_by_path(struct XorrisO *xorriso,
char *in_path, char *eff_path,
IsoNode **node, int flag)
{
int ret;
char *path= NULL;
IsoImage *volume;
Xorriso_alloc_meM(path, char, SfileadrL);
ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, in_path, path, 0);
if(ret<=0)
goto ex;
if(eff_path!=NULL)
strcpy(eff_path, path);
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
goto ex;
ret= Xorriso_node_from_path(xorriso, volume, path, node, 0);
if(ret<=0)
{ret= 0; goto ex;}
ret= 1;
ex:;
Xorriso_free_meM(path);
return(ret);
}
/* @param flag
*/
int Xorriso_node_get_dev(struct XorrisO *xorriso, IsoNode *node,
char *path, dev_t *dev, int flag)
{
*dev= iso_special_get_dev((IsoSpecial *) node);
return(1);
}
/* @param flag bit0= *node is already valid
bit1= add extra block for size estimation
bit2= complain loudely if path is missing in image
bit3= stbuf is to be used without eventual ACL
bit4= try to obtain a better st_nlink count if hardlinks
are enabled
*/
int Xorriso_fake_stbuf(struct XorrisO *xorriso, char *path, struct stat *stbuf,
IsoNode **node, int flag)
{
int ret, min_hl, max_hl, node_idx, i;
IsoImage *volume;
IsoBoot *bootcat;
uint32_t lba;
char *catcontent = NULL;
off_t catsize;
dev_t dev_number;
memset((char *) stbuf, 0, sizeof(struct stat));
if(!(flag&1)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(-1);
ret= Xorriso_node_from_path(xorriso, volume, path, node, !(flag&4));
if(ret<=0)
*node= NULL;
}
if(*node==NULL)
return(0);
/* >>> stbuf->st_dev */
/* >>> stbuf->st_ino */
if(flag & 8)
stbuf->st_mode= iso_node_get_perms_wo_acl(*node) & 07777;
else
stbuf->st_mode= iso_node_get_permissions(*node) & 07777;
if(LIBISO_ISDIR(*node))
stbuf->st_mode|= S_IFDIR;
else if(LIBISO_ISREG(*node))
stbuf->st_mode|= S_IFREG;
else if(LIBISO_ISLNK(*node))
stbuf->st_mode|= S_IFLNK;
else if(LIBISO_ISCHR(*node)) {
stbuf->st_mode|= S_IFCHR;
Xorriso_node_get_dev(xorriso, *node, path, &(stbuf->st_rdev), 0);
} else if(LIBISO_ISBLK(*node)) {
stbuf->st_mode|= S_IFBLK;
/* ts B11124:
Debian mips and mipsel have sizeof(stbuf.st_rdev) == 4
whereas sizeof(dev_t) is 8.
This workaround assumes that the returned numbers fit into 4 bytes.
The may stem from the local filesystem or from the ISO image.
At least there will be no memory corruption but only an integer rollover.
*/
Xorriso_node_get_dev(xorriso, *node, path, &dev_number, 0);
stbuf->st_rdev= dev_number;
} else if(LIBISO_ISFIFO(*node))
stbuf->st_mode|= S_IFIFO;
else if(LIBISO_ISSOCK(*node))
stbuf->st_mode|= S_IFSOCK;
else if(LIBISO_ISBOOT(*node))
stbuf->st_mode|= Xorriso_IFBOOT;
/* >>> With directories this should be : number of subdirs + 2 */
/* >>> ??? How to obtain RR hardlink number for other types ? */
/* This may get overriden farther down */
stbuf->st_nlink= 1;
stbuf->st_uid= iso_node_get_uid(*node);
stbuf->st_gid= iso_node_get_gid(*node);
if(LIBISO_ISREG(*node))
stbuf->st_size= iso_file_get_size((IsoFile *) *node)+ (2048 * !!(flag&2));
else if(LIBISO_ISBOOT(*node)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret <= 0)
return(-1);
ret= iso_image_get_bootcat(volume, &bootcat, &lba, &catcontent, &catsize);
if(catcontent != NULL)
free(catcontent);
if(ret < 0) {
Xorriso_process_msg_queues(xorriso,0);
return(-1);
}
stbuf->st_size= catsize;
} else
stbuf->st_size= 0;
stbuf->st_blksize= 2048;
stbuf->st_blocks= stbuf->st_size / (off_t) 2048;
if(stbuf->st_blocks * (off_t) 2048 != stbuf->st_size)
stbuf->st_blocks++;
stbuf->st_atime= iso_node_get_atime(*node);
stbuf->st_mtime= iso_node_get_mtime(*node);
stbuf->st_ctime= iso_node_get_ctime(*node);
if(LIBISO_ISDIR(*node) || (xorriso->ino_behavior & 1) || (!(flag & 16)) ||
xorriso->hln_array == NULL)
return(1);
/* Try to obtain a better link count */
ret= Xorriso_search_hardlinks(xorriso, *node, &node_idx, &min_hl, &max_hl, 0);
if(ret < 0)
return(ret);
if(ret > 0 && node_idx >= 0) {
for(i= min_hl; i <= max_hl; i++) {
if(i == node_idx)
continue;
/* Check whether node is still valid */
if(iso_node_get_parent(xorriso->hln_array[i]) != NULL)
stbuf->st_nlink++;
}
}
return(1);
}
/* @param flag >>> bit0= follow links (i.e. stat() rather than lstat()
bit1= do not return -2 on severe errors
bit2= complain loudely if path is missing in image
*/
int Xorriso_iso_lstat(struct XorrisO *xorriso, char *path, struct stat *stbuf,
int flag)
{
int ret;
IsoNode *node;
if(flag&1) {
/* >>> follow link in ISO image */;
}
ret= Xorriso_fake_stbuf(xorriso, path, stbuf, &node, flag&4);
if(ret>0)
return(0);
if(ret<0 && !(flag&2))
return(-2);
return(-1);
}
int Xorriso_node_is_valid(struct XorrisO *xorriso, IsoNode *in_node, int flag)
{
IsoNode *node, *parent;
for(node= in_node; 1; node= parent) {
parent= (IsoNode *) iso_node_get_parent(node);
if(parent == node)
break;
if(parent == NULL)
return(0); /* Node is not in the tree (any more) */
}
return(1);
}
int Xorriso_path_from_node(struct XorrisO *xorriso, IsoNode *in_node,
char path[SfileadrL], int flag)
{
int ret, i, comp_count= 0;
IsoNode *node, *parent, **components= NULL;
char *wpt, *npt;
for(node= in_node; 1; node= parent) {
parent= (IsoNode *) iso_node_get_parent(node);
if(parent == node)
break;
if(parent == NULL)
return(0); /* Node is not in the tree (any more) */
comp_count++;
}
if(comp_count == 0) {
strcpy(path, "/");
return(1);
}
components= calloc(comp_count, sizeof(IsoNode *));
if(components == NULL) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
ret= -1; goto ex;
}
i= comp_count;
for(node= in_node; 1; node= parent) {
parent= (IsoNode *) iso_node_get_parent(node);
if(parent == node)
break;
components[--i]= node;
}
wpt= path;
for(i= 0; i < comp_count; i++) {
npt= (char *) iso_node_get_name(components[i]);
if((wpt - path) + strlen(npt) + 1 >= SfileadrL) {
/* >>> path is getting much too long */;
ret= -1; goto ex;
}
*(wpt++)= '/';
strcpy(wpt, npt);
wpt+= strlen(npt);
*wpt= 0;
}
ret= 1;
ex:;
if(components != NULL)
free(components);
return(ret);
}
/* <<< The lookup from node pointer will be done by Xorriso_path_from_node()
(Currently it runs a full tree traversal)
Parameter node and flag bit0 will vanish then
*/
/* @param flag bit0= use lba rather than node pointer
*/
int Xorriso_path_from_lba(struct XorrisO *xorriso, IsoNode *node, int lba,
char path[SfileadrL], int flag)
{
int ret;
struct FindjoB *job= NULL;
struct stat dir_stbuf;
char *found_path;
path[0]= 0;
if((flag & 1) && lba <= 0)
return(0);
ret= Findjob_new(&job, "/", 0);
if(ret <= 0) {
Xorriso_no_findjob(xorriso, "path_from_node", 0);
return(ret);
}
if(flag & 1)
Findjob_set_lba_range(job, lba, 1, 0);
else
Findjob_set_wanted_node(job, (void *) node, 0);
Findjob_set_action_found_path(job, 0);
ret= Xorriso_findi(xorriso, job, NULL, (off_t) 0,
NULL, "/", &dir_stbuf, 0, 0);
if(ret > 0) {
ret= 1;
Findjob_get_found_path(job, &found_path, 0);
if(found_path == NULL)
ret= 0;
else if(Sfile_str(path, found_path, 0) <= 0)
ret= -1;
}
Findjob_destroy(&job, 0);
return(ret);
}
/* @param flag bit0= in_node is valid, do not resolve iso_adr
bit2= recognize and parse split parts despite
xorrio->split_size <= 0
*/
int Xorriso_identify_split(struct XorrisO *xorriso, char *iso_adr,
void *in_node,
struct SplitparT **parts, int *count,
struct stat *total_stbuf, int flag)
{
int ret, i, incomplete= 0, overlapping= 0;
int partno, total_parts, first_total_parts= -1;
off_t offset, bytes, total_bytes, first_total_bytes= -1, first_bytes= -1;
off_t size, covered;
IsoImage *volume;
IsoDir *dir_node;
IsoDirIter *iter= NULL;
IsoNode *node;
char *name;
struct stat stbuf, first_stbuf;
*count= 0;
*parts= NULL;
if(xorriso->split_size <= 0 && !(flag & 4))
return(0);
if(flag&1) {
node= (IsoNode *) in_node;
} else {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
return(-1);
ret= Xorriso_node_from_path(xorriso, volume, iso_adr, &node, 1);
if(ret<=0)
return(-1);
}
if(!LIBISO_ISDIR(node))
return(0);
dir_node= (IsoDir *) node;
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0) {
cannot_iter:;
Xorriso_cannot_create_iter(xorriso, ret, 0);
return(-1);
}
for(i= 0; iso_dir_iter_next(iter, &node) == 1; i++) {
name= (char *) iso_node_get_name(node);
ret= Splitpart__parse(name, &partno, &total_parts,
&offset, &bytes, &total_bytes, 0);
if(ret<=0)
{ret= 0; goto ex;}
if(i==0) {
first_total_parts= total_parts;
first_bytes= bytes;
first_total_bytes= total_bytes;
Xorriso_fake_stbuf(xorriso, "", &first_stbuf, &node, 1);
size= first_stbuf.st_size;
} else {
if(first_total_parts!=total_parts || first_total_bytes!=total_bytes ||
(first_bytes!=bytes && partno!=total_parts))
{ret= 0; goto ex;}
Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
if(first_stbuf.st_mode != stbuf.st_mode ||
first_stbuf.st_uid != stbuf.st_uid ||
first_stbuf.st_gid != stbuf.st_gid ||
first_stbuf.st_mtime != stbuf.st_mtime ||
first_stbuf.st_ctime != stbuf.st_ctime)
{ret= 0; goto ex;}
size= stbuf.st_size;
}
/* check for plausible size */
if(!((partno != total_parts && size == bytes) ||
(partno == total_parts && size <= bytes)))
{ret= 0; goto ex;}
if(offset != first_bytes * (off_t) (partno - 1))
{ret= 0; goto ex;}
(*count)++;
}
if(*count <= 0 || *count != first_total_parts)
{ret= 0; goto ex;}
ret= Splitparts_new(parts, (*count)+1, 0); /* (have one end marker item) */
if(ret<=0)
return(ret);
iso_dir_iter_free(iter);
ret= iso_dir_get_children(dir_node, &iter);
if(ret<0)
goto cannot_iter;
for(i= 0; i<*count; i++) {
ret= iso_dir_iter_next(iter, &node);
if(ret!=1)
break;
name= (char *) iso_node_get_name(node);
ret= Splitpart__parse(name, &partno, &total_parts,
&offset, &bytes, &total_bytes, 0);
if(ret<=0)
{ret= 0; goto ex;}
ret= Splitparts_set(*parts, i, name, partno, total_parts, offset, bytes,
total_bytes, 0);
if(ret<=0)
goto ex;
}
Splitparts_sort(*parts, *count, 0);
covered= 0;
for(i= 0; i<*count; i++) {
Splitparts_get(*parts, i, &name, &partno, &total_parts, &offset, &bytes,
&total_bytes, 0);
if(offset>covered)
incomplete= 1;
else if(offset<covered)
overlapping= 1;
if(offset+bytes > covered)
covered= offset+bytes;
}
if(total_bytes>covered)
incomplete= 1;
memcpy(total_stbuf, &first_stbuf, sizeof(struct stat));
total_stbuf->st_size= total_bytes;
ret= !(overlapping || incomplete);
ex:;
if(iter!=NULL)
iso_dir_iter_free(iter);
return(ret);
}
/* @param flag bit0= node is valid, do not resolve path
bit1= insist in complete collection of part files
*/
int Xorriso_is_split(struct XorrisO *xorriso, char *path, void *node,
int flag)
{
struct SplitparT *split_parts= NULL;
int split_count= 0, ret;
struct stat stbuf;
ret= Xorriso_identify_split(xorriso, path, node, &split_parts,
&split_count, &stbuf, flag & 3);
if(split_parts!=NULL)
Splitparts_destroy(&split_parts, split_count, 0);
return(ret>0);
}
/* @param node Opaque handle to IsoNode which is to be inquired instead of path if it is not NULL.
@param path is used as address if node is NULL.
@param acl_text if acl_text is not NULL, then *acl_text will be set to the
ACL text (without comments) of the file object. In this
case it finally has to be freed by the caller.
@param flag bit0= do not report to result but only retrieve ACL text
bit1= check for existence of true ACL (not fabricated),
do not allocate and set acl_text but return 1 or 2
bit2-3: what ALC to retrieve:
0= "access" and "default", mark "default:"
1= "access" only
2= "default" only, do not mark "default:"
bit4= get "access" ACL only if not trivial
@return 2 ok, no ACL available, eventual *acl_text will be NULL
1 ok, ACL available, eventual *acl_text stems from malloc()
<=0 error
*/
int Xorriso_getfacl(struct XorrisO *xorriso, void *in_node, char *path,
char **acl_text, int flag)
{
int ret, d_ret, result_len= 0, pass, what;
IsoNode *node;
char *text= NULL, *d_text= NULL, *cpt, *npt;
uid_t uid;
gid_t gid;
struct passwd *pwd;
struct group *grp;
what= (flag >> 2) & 3;
if(acl_text != NULL)
*acl_text= NULL;
node= (IsoNode *) in_node;
if(node == NULL) {
ret= Xorriso_get_node_by_path(xorriso, path, NULL, &node, 0);
if(ret<=0)
goto ex;
}
ret= iso_node_get_acl_text(node, &text, &d_text, flag & 16);
d_ret= (d_text != NULL);
if(ret < 0 || d_ret < 0) {
if(path != NULL && path[0] != 0) {
strcpy(xorriso->info_text, "Error with obtaining ACL of ");
Text_shellsafe(path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
}
ret= 0; goto ex;
}
if(flag & 2) {
ret= 1 + (ret != 1 && d_ret == 0);
goto ex;
}
if((ret == 0 || ret == 2) && d_ret == 0) {
if(flag & 1) {
ret= 1 + (ret == 0);
goto ex;
}
strcpy(xorriso->info_text, "No ACL associated with ");
Text_shellsafe(path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
if(ret == 0)
{ret= 2; goto ex;}
}
if(!(flag & 1)) {
ret= Xorriso_getfname(xorriso, path, 0);
if(ret <= 0)
goto ex;
uid= iso_node_get_uid(node);
pwd= getpwuid(uid);
if(pwd == NULL)
sprintf(xorriso->result_line, "# owner: %.f\n", (double) uid);
else
sprintf(xorriso->result_line, "# owner: %s\n", pwd->pw_name);
Xorriso_result(xorriso, 0);
gid= iso_node_get_gid(node);
grp= getgrgid(gid);
if(grp == NULL)
sprintf(xorriso->result_line, "# group: %.f\n", (double) gid);
else
sprintf(xorriso->result_line, "# group: %s\n", grp->gr_name);
Xorriso_result(xorriso, 0);
}
for(pass= 0; pass < 1 + (acl_text != NULL && !(flag & 2)); pass++) {
if(pass) {
if(result_len == 0)
break;
*acl_text= calloc(result_len + 1, 1);
if(*acl_text == NULL) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
ret= -1; goto ex;
}
}
if(text != NULL && what <= 1) {
for(npt= cpt= text; npt != NULL; cpt= npt + 1) {
npt= strchr(cpt, '\n');
if(npt != NULL)
*npt= 0;
if(*cpt == 0) {
if(d_text != NULL || pass) {
if(npt != NULL)
*npt= '\n';
continue;
}
} else
result_len+= strlen(cpt) + 1;
if(pass) {
sprintf(*acl_text + strlen(*acl_text), "%s\n", cpt);
} else if(!(flag & 1)) {
Sfile_str(xorriso->result_line, cpt, 0);
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
}
if(npt != NULL)
*npt= '\n';
}
}
if(d_text != NULL && (what == 0 || what == 2)) {
for(npt= cpt= d_text; npt != NULL; cpt= npt + 1) {
npt= strchr(cpt, '\n');
if(npt != NULL)
*npt= 0;
if(*cpt != 0) {
if(pass) {
if(what == 0)
sprintf(*acl_text + strlen(*acl_text), "default:%s\n", cpt);
else
sprintf(*acl_text + strlen(*acl_text), "%s\n", cpt);
} else {
xorriso->result_line[0]= 0;
if(what == 0)
Sfile_str(xorriso->result_line, "default:", 0);
Sfile_str(xorriso->result_line, cpt, 1);
result_len+= strlen(cpt) + 9;
}
} else
xorriso->result_line[0]= 0;
if(pass== 0 && !(flag & 1)) {
strcat(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
}
if(npt != NULL)
*npt= '\n';
}
}
}
if(result_len == 0) {
if(acl_text != NULL)
*acl_text= NULL;
ret= 2;
} else {
ret= 1;
}
ex:;
iso_node_get_acl_text(node, &text, &d_text, 1 << 15);
return(ret);
}
/*
@param flag bit0= do not report to result but only retrieve attr text
bit1= path is disk_path
bit3= do not ignore eventual non-user attributes.
bit5= in case of symbolic link on disk: inquire link target
bit6= check for existence of xattr, return 0 or 1
(depends also on bit3)
*/
int Xorriso_getfattr(struct XorrisO *xorriso, void *in_node, char *path,
char **attr_text, int flag)
{
int ret= 1, i, bsl_mem, result_len= 0, pass;
size_t num_attrs= 0, *value_lengths= NULL;
char **names= NULL, **values= NULL, *bsl;
if(attr_text != NULL)
*attr_text= NULL;
ret= Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names,
&value_lengths, &values, flag & (2 | 8 | 32));
if(ret <= 0)
goto ex;
if(flag & 64) {
ret= (num_attrs > 0);
goto ex;
}
if(num_attrs == 0)
{ret= 2; goto ex;}
if(!(flag & 1)) {
ret= Xorriso_getfname(xorriso, path, 0);
if(ret <= 0)
goto ex;
}
for(pass= 0; pass < 1 + (attr_text != NULL); pass++) {
if(pass) {
*attr_text= calloc(result_len + 1, 1);
if(*attr_text == NULL) {
Xorriso_no_malloc_memory(xorriso, NULL, 0);
ret= -1; goto ex;
}
}
for(i= 0; i < (int) num_attrs; i++) {
if(strlen(names[i]) + value_lengths[i] >= SfileadrL) {
sprintf(xorriso->result_line, "# oversized: name %d , value %d bytes\n",
(int) strlen(names[i]), (int) value_lengths[i]);
} else {
ret= Sfile_bsl_encoder(&bsl, names[i], strlen(names[i]), 8);
if(ret <= 0)
{ret= -1; goto ex;}
strcpy(xorriso->result_line, bsl);
free(bsl);
ret= Sfile_bsl_encoder(&bsl, values[i], value_lengths[i], 8);
if(ret <= 0)
{ret= -1; goto ex;}
sprintf(xorriso->result_line + strlen(xorriso->result_line),
"=\"%s\"\n", bsl);
free(bsl);
}
/* temporarily disable -backslash_codes with result output */
result_len+= strlen(xorriso->result_line);
if(pass) {
strcat(*attr_text, xorriso->result_line);
} else if(!(flag & 1)) {
bsl_mem= xorriso->bsl_interpretation;
xorriso->bsl_interpretation= 0;
Xorriso_result(xorriso, 0);
xorriso->bsl_interpretation= bsl_mem;
}
}
}
if(!(flag & 1)) {
strcpy(xorriso->result_line, "\n");
Xorriso_result(xorriso, 0);
}
ret= 1;
ex:;
Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names,
&value_lengths, &values, 1 << 15);
return(ret);
}
/*
@param flag bit0= with mode "e" : Use echo -e encoding but
do not put out commands and quotation marks.
Rather apply double backslash.
*/
int Xorriso_append_extattr_comp(struct XorrisO *xorriso,
char *comp, size_t comp_len,
char *mode, int flag)
{
int ret;
char *line, *wpt, *bsl = NULL;
unsigned char *upt, *uval;
line= xorriso->result_line;
uval= (unsigned char *) comp;
if(*mode == 'q') {
Text_shellsafe(comp, line, 1);
} else if(*mode == 'e' || mode[0] == 0) {
for(upt= uval; (size_t) (upt - uval) < comp_len; upt++)
if(*upt <= 037 || *upt >= 0177)
break;
if((size_t) (upt - uval) < comp_len || (flag & 1)) {
/* Use "$(echo -e '\0xyz')" */;
if(!(flag & 1))
strcat(line, "\"$(echo -e '");
wpt= line + strlen(line);
for(upt= uval; (size_t) (upt - uval) < comp_len; upt++) {
if(*upt <= 037 || *upt >= 0177 || *upt == '\\' || *upt == '\'') {
if(flag & 1)
*(wpt++)= '\\';
sprintf((char *) wpt, "\\0%-3.3o", *upt);
wpt+= strlen(wpt);
} else {
*(wpt++)= *upt;
}
}
*wpt= 0;
if(!(flag & 1))
strcpy(wpt, "')\"");
} else {
Text_shellsafe(comp, line, 1);
}
} else if(*mode == 'b') {
ret= Sfile_bsl_encoder(&bsl, comp, comp_len, 8);
if(ret <= 0)
{ret= -1; goto ex;}
strcat(line, bsl);
free(bsl);
bsl= NULL;
} else if(*mode == 'r') {
strcat(line, comp);
}
ret= 1;
ex:;
if(bsl != NULL)
free(bsl);
return(ret);
}
/*
@param flag bit1= path is disk_path
bit3= do not ignore eventual non-user attributes.
bit5= in case of symbolic link on disk: inquire link target
*/
int Xorriso_list_extattr(struct XorrisO *xorriso, void *in_node, char *path,
char *show_path, char *mode, int flag)
{
int ret= 1, i, bsl_mem;
size_t num_attrs= 0, *value_lengths= NULL;
char **names= NULL, **values= NULL, *cpt, *space_pt, *name_pt, *path_pt;
char *line;
unsigned char *upt, *uval;
line= xorriso->result_line;
ret= Xorriso_get_attrs(xorriso, in_node, path, &num_attrs, &names,
&value_lengths, &values, flag & (2 | 8 | 32));
if(ret <= 0)
goto ex;
if(flag & 64) {
ret= (num_attrs > 0);
goto ex;
}
if(num_attrs == 0)
{ret= 2; goto ex;}
strcpy(line, "n=");
path_pt= show_path + (show_path[0] == '/');
if(path_pt[0] == 0)
path_pt= ".";
ret= Xorriso_append_extattr_comp(xorriso, path_pt, strlen(path_pt), mode, 0);
if(ret <= 0)
goto ex;
strcat(line, "\n");
Xorriso_result(xorriso, 0);
for(i= 0; i < (int) num_attrs; i++) {
line[0]= 0;
uval= (unsigned char *) values[i];
if(strlen(names[i]) + value_lengths[i] >= SfileadrL) {
sprintf(line,
"echo 'OMITTED: Oversized: name %d bytes, value %d bytes in file '\"$n\" >&2\n",
(int) strlen(names[i]), (int) value_lengths[i]);
Xorriso_result(xorriso, 0);
continue;
}
/* Form: $c space name value $n */
/* Split namespace from name */
cpt= strchr(names[i], '.');
if(cpt == NULL) {
space_pt= "user";
name_pt= names[i];
} else {
*cpt= 0;
space_pt= names[i];
name_pt= cpt + 1;
}
/* FreeBSD setextattr cannot set 0-bytes */
for(upt= uval; (size_t) (upt - uval) < value_lengths[i]; upt++)
if(*upt == 0
)
break;
if((size_t) (upt - uval) < value_lengths[i]) {
strcpy(line, "echo 'OMITTED: Value contains 0-bytes : space \"'\"");
Xorriso_append_extattr_comp(xorriso, space_pt, strlen(space_pt), "e", 1);
if(ret <= 0)
goto ex;
strcat(line, "\"'\" , name \"'\"");
Xorriso_append_extattr_comp(xorriso, name_pt, strlen(name_pt), "e", 1);