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.
 
 
 
 
 
 
libisoburn/xorriso/xorriso.c

12671 lines
356 KiB

/*
( cd .. ; libisoburn-develop/xorriso/compile_xorriso.sh -g )
or
cc -g -DXorriso_with_maiN -DXorriso_with_readlinE \
-DXorriso_build_timestamP='"'"$(date -u '+%Y.%m.%d.%H%M%S')"'"' \
-Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
-o xorriso/xorriso \
xorriso/xorriso.c xorriso/xorrisoburn.c \
-lpthread -lreadline -lburn -lisofs -lisoburn
or
cc -g -DXorriso_with_readlinE \
-DXorriso_build_timestamP='"'"$(date -u '+%Y.%m.%d.%H%M%S')"'"' \
-Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
-c \
xorriso/xorriso.c xorriso/xorrisoburn.c
*/
/* Command line oriented batch and dialog tool which creates, loads,
manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2008 Thomas Schmitt, <scdbackup@gmx.net>
Initial code of this program was derived from program src/askme.c out
of scdbackup-0.8.8, Copyright 2007 Thomas Schmitt, BSD-License.
Provided under GPL version 2, with the announcement that this might
get changed in future. I would prefer BSD or a modified LGPL with no
option to choose any kind of future GPL version.
(This announcement affects only future releases of xorriso.
If you obtain a copy licensed as "GPL version 2" then this license is
not revocable for that particular copy, of course.)
Overview of xorriso architecture:
libburn provides the ability to read and write data.
libisofs interprets and manipulates ISO 9660 directory trees. It generates
the output stream which is handed over to libburn.
libisoburn encapsulates the connectivity issues between libburn and
libisofs. It also enables multi-session emulation on overwritable media
and random access file objects.
xorriso is intended as reference application of libisoburn.
xorrisoburn.[ch] encapsulate any usage of the libraries by xorriso.
xorriso.h exposes the public functions of xorriso which are intended
to be used by programs which link with xorriso.o. These functions are
direct equivalents of the xorriso interpreter commands.
There is also the API for handling event messages.
xorriso_private.h is not to be included by other software. It encapsulates
the inner interfaces of xorriso.
xorriso.c provides the command interpreter as described in xorriso.1.
It performs any activity that does not demand a reference to a symbol
of the library APIs. This includes:
- Interpretation of user input from arguments, dialog, and scripting.
- Output of result text and event messages.
- POSIX filesystem operations.
- Public functions which perform the particular xorriso commands.
- The main() function, if enabled by #define Xorriso_with_maiN.
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <dirent.h>
#include <time.h>
#include <utime.h>
#include <pwd.h>
#include <grp.h>
/* eventually, this is done in xorriso_private.h : #include <regex.h> */
#ifdef Xorriso_with_readlinE
#ifdef Xorriso_with_old_readlinE
#include <readline.h>
#include <history.h>
#else /* Xorriso_with_old_readlinE */
#include <readline/readline.h>
#include <readline/history.h>
#endif /* ! Xorriso_with_old_readlinE */
#endif /* Xorriso_with_readlinE */
#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));
/* Diet facility: exclude help texts from binaries */
/* This will eventually be redefined to eat up its content */
#define AlN(x) x
/* There is only one stage of diet: Xorriso_no_helP */
#ifdef Xorriso_no_helP
#undef AlN
#define AlN(x)
#endif
/* ------------------------------------------------------------------------ */
/* The official xorriso options API. "No shortcuts" */
#include "xorriso.h"
/* The inner isofs- and burn-library interface */
#include "xorrisoburn.h"
/* The inner description of XorrisO */
#define Xorriso_is_xorriso_selF 1
#include "xorriso_private.h"
/* ------------------------------------------------------------------------ */
#ifndef Xorriso_sfile_externaL
char *Sfile_fgets(char *line, int maxl, FILE *fp)
{
int l;
char *ret;
ret= fgets(line,maxl,fp);
if(ret==NULL)
return(NULL);
l= strlen(line);
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
if(l>0) if(line[l-1]=='\n') line[--l]= 0;
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
return(ret);
}
int Sfile_count_components(char *path, int flag)
/*
bit0= do not ignore trailing slash
bit1= do not ignore empty components (other than the empty root name)
*/
{
int l,count= 0;
char *cpt;
l= strlen(path);
if(l==0)
return(0);
count= 1;
for(cpt= path+l-1;cpt>=path;cpt--) {
if(*cpt=='/') {
if(*(cpt+1)==0 && !(flag&1))
continue;
if(*(cpt+1)=='/' && !(flag&2))
continue;
count++;
}
}
return(count);
}
int Sfile_component_pointer(char *path, char **sourcept, int idx, int flag)
/*
bit0= do not ignore trailing slash
bit1= do not ignore empty components (other than the empty root name)
bit2= accept 0 as '/'
*/
{
int count= 0;
char *spt;
for(spt= path;*spt!=0 || (flag&4);spt++) {
if(count>=idx) {
*sourcept= spt;
return(1);
}
if(*spt=='/' || *spt==0) {
if(*(spt+1)=='/' && !(flag&2))
continue;
if(*(spt+1)==0 && !(flag&1))
continue;
count++;
}
}
if((flag&1) && count>=idx)
return(1);
return(0);
}
int Sfile_leafname(char *path, char leafname[SfileadrL], int flag)
{
int count, ret;
char *lpt;
leafname[0]= 0;
count= Sfile_count_components(path, 0);
if(count==0)
return(0);
ret= Sfile_component_pointer(path, &lpt, count-1, 0);
if(ret<=0)
return(ret);
if(Sfile_str(leafname, lpt, 0)<=0)
return(0);
lpt= strchr(leafname, '/');
if(lpt!=NULL)
*lpt= 0;
return(1);
}
int Sfile_add_to_path(char path[SfileadrL], char *addon, int flag)
{
int l;
l= strlen(path);
if(l+1>=SfileadrL)
return(0);
if(l==0) {
strcpy(path,"/");
l= 1;
} else if(path[l-1]!='/') {
path[l++]= '/';
path[l]= 0;
}
if(l+strlen(addon)>=SfileadrL)
return(0);
if(addon[0]=='/')
strcpy(path+l,addon+1);
else
strcpy(path+l,addon);
return(1);
}
int Sfile_prepend_path(char *prefix, char path[SfileadrL], int flag)
{
int l, i;
l= strlen(path)+strlen(prefix)+1;
if(l>=SfileadrL) {
#ifdef Not_yeT
/* >>> ??? how to transport messages to xorriso ? */
sprintf(xorriso->info_text,
"Combination of wd and relative address too long (%d > %d)",
l,SfileadrL-1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
#endif
return(-1);
}
l-= strlen(path);
for(i= strlen(path)+1; i>=0; i--)
path[i+l]= path[i];
strcpy(path,prefix);
path[l-1]= '/';
return(1);
}
int Sfile_being_group_member(struct stat *stbuf, int flag)
{
int i, suppl_groups;
gid_t *suppl_glist;
if (getegid()==stbuf->st_gid)
return(1);
suppl_groups= getgroups(0, NULL);
suppl_glist= (gid_t *) malloc((suppl_groups + 1) * sizeof(gid_t));
if (suppl_glist==NULL)
return(-1);
suppl_groups= getgroups(suppl_groups+1,suppl_glist);
for (i= 0; i<suppl_groups; i++) {
if (suppl_glist[i]==stbuf->st_gid) {
free((char *) suppl_glist);
return(1);
}
}
free((char *) suppl_glist);
return(0);
}
int Sfile_type(char *filename, int flag)
/*
bit0= return -1 if file is missing
bit1= return a hardlink with siblings as type 5
bit2= evaluate eventual link target rather than the link object itself
bit3= return a socket or a char device as types 7 or 8 rather than 0
*/
/*
return:
0=unknown
1=regular
2=directory
3=symbolic link
4=named pipe
5=multiple hardlink (with bit1)
6=block device
7=socket (with bit3)
8=character device (with bit3)
*/
{
struct stat stbuf;
if(flag&4) {
if(stat(filename,&stbuf)==-1) {
if(flag&1) return(-1);
else return(0);
}
} else {
if(lstat(filename,&stbuf)==-1) {
if(flag&1) return(-1);
else return(0);
}
}
if(S_ISREG(stbuf.st_mode)) {
if(flag&2)
if(stbuf.st_nlink>1)
return(5);
return(1);
}
if(S_ISDIR(stbuf.st_mode))
return(2);
if((stbuf.st_mode&S_IFMT)==S_IFLNK)
return(3);
if(S_ISFIFO(stbuf.st_mode))
return(4);
if(S_ISBLK(stbuf.st_mode))
return(6);
if(flag&8)
if((stbuf.st_mode&S_IFMT)==S_IFSOCK)
return(7);
if(flag&8)
if(S_ISCHR(stbuf.st_mode))
return(8);
return(0);
}
char *Sfile_datestr(time_t tim, short int flag)
/*
bit0=with hours+minutes
bit1=with seconds
bit8= local time rather than UTC
*/
{
static char zeitcode[80]={"000000"};
char puff[80];
struct tm *azt;
if(flag&256)
azt = localtime(&tim);
else
azt = gmtime(&tim);
if(azt->tm_year>99)
sprintf(zeitcode,"%c%1.1d%2.2d%2.2d",
'A'+(azt->tm_year-100)/10,azt->tm_year%10,
azt->tm_mon+1,azt->tm_mday);
else
sprintf(zeitcode,"%2.2d%2.2d%2.2d",
azt->tm_year,azt->tm_mon+1,azt->tm_mday);
if(flag&1){
sprintf(puff,".%2.2d%2.2d",azt->tm_hour,azt->tm_min);
strcat(zeitcode,puff);
}
if(flag&2){
sprintf(puff,"%2.2d",azt->tm_sec);
strcat(zeitcode,puff);
}
return(zeitcode);
}
int Sfile_scale(double value, char *result, int siz, double thresh, int flag)
/*
bit0= eventually ommit 'b'
bit1= make text as short as possible
bit2= no fraction (if it would fit at all)
*/
{
char scale_c,scales[6],form[80];
int i,dec_siz= 0,avail_siz= 1;
strcpy(scales,"bkmgtp");
scale_c= scales[0];
for(i=1;scales[i]!=0;i++) {
if(value<thresh-0.5)
break;
value/= 1024.0;
scale_c= scales[i];
}
if(scale_c!='b' && !(flag&4)) { /* is there room for fractional part ? */
avail_siz= siz-1;
sprintf(form,"%%.f");
sprintf(result,"%.f",value);
if(strlen(result)<=avail_siz-2)
dec_siz= 1; /* we are very modest */
}
if(scale_c=='b' && (flag&1)) {
if(flag&2)
sprintf(form,"%%.f");
else
sprintf(form,"%%%d.f",siz);
sprintf(result,form,value);
} else {
if(flag&2)
sprintf(form,"%%.f%%c");
else if(dec_siz>0)
sprintf(form,"%%%d.%df%%c",avail_siz,dec_siz);
else
sprintf(form,"%%%d.f%%c",siz-1);
sprintf(result,form,value,scale_c);
}
return(1);
}
int Sfile_off_t_text(char text[80], off_t num, int flag)
{
char *tpt;
off_t hnum, scale= 1;
int digits= 0, d, i;
tpt= text;
hnum= num;
if(hnum<0) {
*(tpt++)= '-';
hnum= -num;
}
if(hnum<0) { /* it can stay nastily persistent */
strcpy(text, "_overflow_");
return(0);
}
for(i= 0; i<23; i++) { /* good for up to 70 bit = 10 exp 21.07... */
if(hnum==0)
break;
hnum/= 10;
if(hnum)
scale*= 10;
}
if(i==0) {
strcpy(text, "0");
return(1);
}
if(i==23) {
strcpy(text, "_overflow_");
return(0);
}
digits= i;
hnum= num;
for(; i>0; i--) {
d= hnum/scale;
tpt[digits-i]= '0'+d;
hnum= hnum%scale;
scale/= 10;
}
tpt[digits]= 0;
return(1);
}
int Sfile_destroy_argv(int *argc, char ***argv, int flag)
{
int i;
if(*argc>0 && *argv!=NULL){
for(i=0;i<*argc;i++){
if((*argv)[i]!=NULL)
Smem_freE((*argv)[i]);
}
Smem_freE((char *) *argv);
}
*argc= 0;
*argv= NULL;
return(1);
}
int Sfile_make_argv(char *progname, char *line, int *argc, char ***argv,
int flag)
/*
bit0= read progname as first argument from line
bit1= just release argument list argv and return
bit2= abort with return(0) if incomplete quotes are found
bit3= eventually prepend missing '-' to first argument read from line
*/
{
int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc;
char *cpt,*start;
char buf[SfileadrL];
Sfile_destroy_argv(argc,argv,0);
if(flag&2) return(1);
for(pass=0;pass<2;pass++) {
cpt= line-1;
if(!(flag&1)){
argzaehl= line_start_argc= 1;
if(pass==0)
maxl= strlen(progname);
else
strcpy((*argv)[0],progname);
} else {
argzaehl= line_start_argc= 0;
if(pass==0) maxl= 0;
}
while(*(++cpt)!=0){
if(isspace(*cpt)) continue;
start= cpt;
buf[0]= 0;
cpt--;
while(*(++cpt)!=0) {
if(isspace(*cpt)) break;
if(*cpt=='"'){
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
l= strlen(buf);
start= cpt+1;
while(*(++cpt)!=0) if(*cpt=='"') break;
if((flag&4) && *cpt==0)
return(0);
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
start= cpt+1;
}else if(*cpt=='\''){
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
l= strlen(buf);
start= cpt+1;
while(*(++cpt)!=0) if(*cpt=='\'') break;
if((flag&4) && *cpt==0)
return(0);
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
start= cpt+1;
}
if(*cpt==0) break;
}
l= cpt-start;
bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
l= strlen(buf);
if(pass==0){
if(argzaehl==line_start_argc && (flag&8))
if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
l++;
if(l>maxl) maxl= l;
}else{
strcpy((*argv)[argzaehl],buf);
if(argzaehl==line_start_argc && (flag&8))
if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
sprintf((*argv)[argzaehl],"-%s", buf);
}
argzaehl++;
if(*cpt==0) break;
}
if(pass==0){
*argc= argzaehl;
if(argzaehl>0) {
*argv= (char **) Smem_malloC(argzaehl*sizeof(char *));
if(*argv==NULL)
return(-1);
}
for(i=0;i<*argc;i++) {
(*argv)[i]= (char *) Smem_malloC((maxl+1));
if((*argv)[i]==NULL)
return(-1);
}
}
}
return(1);
}
/* @param flag bit0= append */
int Sfile_str(char target[SfileadrL], char *source, int flag)
{
int l;
l= strlen(source);
if(flag&1)
l+= strlen(target);
if(l>=SfileadrL) {
fprintf(stderr, "--- Path string overflow (%d > %d). Malicious input ?\n",
l,SfileadrL-1);
return(0);
}
if(flag&1)
strcat(target, source);
else
strcpy(target, source);
return(1);
}
/** Combine environment variable HOME with given filename
@param filename Address relative to $HOME
@param fileadr Resulting combined address
@param fa_size Size of array fileadr
@param flag Unused yet
@return 1=ok , 0=no HOME variable , -1=result address too long
*/
int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
{
char *home;
strcpy(fileadr,filename);
home= getenv("HOME");
if(home==NULL)
return(0);
if(strlen(home)+strlen(filename)+1>=fa_size)
return(-1);
strcpy(fileadr,home);
if(filename[0]!=0){
strcat(fileadr,"/");
strcat(fileadr,filename);
}
return(1);
}
/** Return a double representing seconds and microseconds since 1 Jan 1970 */
double Sfile_microtime(int flag)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
return((double) (tv.tv_sec+1.0e-6*tv.tv_usec));
}
int Sfile_decode_datestr(struct tm *reply, char *text, int flag)
/* YYMMDD[.hhmm[ss]] */
{
int i,l;
time_t current_time;
struct tm *now;
current_time= time(0);
now= localtime(&current_time);
for(i=0;i<sizeof(struct tm);i++)
((char *) reply)[i]= ((char *) now)[i];
if(text[0]<'0'|| (text[0]>'9' && text[0]<'A') || text[0]>'Z')
return(0);
l= strlen(text);
for(i=1;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=6)
return(0);
if(text[i]==0)
goto decode;
if(text[i]!='.' || (l!=11 && l!=13))
return(0);
for(i++;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=l)
return(0);
decode:;
reply->tm_hour= 0;
reply->tm_min= 0;
reply->tm_sec= 0;
i= 0;
if(text[0]>='A')
reply->tm_year= 100+(text[i]-'A')*10+text[1]-'0';
else
reply->tm_year= 10*(text[0]-'0')+text[1]-'0';
reply->tm_mon= 10*(text[2]-'0')+text[3]-'0'-1;
reply->tm_mday= 10*(text[4]-'0')+text[5]-'0';
if(l==6)
return(1);
reply->tm_hour= 10*(text[7]-'0')+text[8]-'0';
reply->tm_min= 10*(text[9]-'0')+text[10]-'0';
if(l==11)
return(1);
reply->tm_sec= 10*(text[11]-'0')+text[12]-'0';
return(1);
}
#endif /* Xorriso_sfile_externaL */
/* --------------------------------- misc --------------------------------- */
int Write_to_channel(char *text, int channel_no, int flag)
/*
bit0= packet write disabled, write to stdin resp. stderr
bit1= text is the name of the log file for the given channel
bit2= text is the name of the consolidated packet log file for all channels
bit15= with bit1 or bit2: close depicted log file
*/
{
char *rpt,*npt,ret= 1;
char prefix[16];
static int num_channels= 4;
static char channel_prefixes[4][4]= {".","R","I","M"};
static FILE *logfile_fp[4]= {NULL,NULL,NULL,NULL};
static FILE *pktlog_fp= NULL;
if(channel_no<0 || channel_no>=num_channels)
return(-1);
/* Logfiles */
if((flag&2) && logfile_fp[channel_no]!=NULL) {
fprintf(logfile_fp[channel_no],
"! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fclose(logfile_fp[channel_no]);
logfile_fp[channel_no]= NULL;
}
if((flag&4) && pktlog_fp!=NULL) {
fprintf(pktlog_fp,
"I:1:! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fclose(pktlog_fp);
pktlog_fp= NULL;
}
if(flag&(1<<15))
return(1);
if((flag&2)) {
logfile_fp[channel_no]= fopen(text,"a");
if(logfile_fp[channel_no]==NULL)
return(0);
fprintf(logfile_fp[channel_no],
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fflush(logfile_fp[channel_no]);
}
if((flag&4)) {
pktlog_fp= fopen(text,"a");
if(pktlog_fp==NULL)
return(0);
fprintf(pktlog_fp,
"I:1:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : . : %s\n",
Sfile_datestr(time(0),1|2|256));
fflush(pktlog_fp);
}
if(flag&(2|4))
return(1);
if(flag&1) {
if(channel_no==1 || channel_no==3)
printf("%s",text);
if(channel_no==2 || channel_no==3)
fprintf(stderr,"%s",text);
if(logfile_fp[channel_no]!=NULL) {
fprintf(logfile_fp[channel_no],"%s",text);
fflush(logfile_fp[channel_no]);
}
if(pktlog_fp!=NULL)
return(1);
}
rpt= text;
sprintf(prefix,"%s:x: ",channel_prefixes[channel_no]);
while(*rpt!=0) {
npt= strchr(rpt,'\n');
if(npt==NULL)
prefix[2]= '0';
else
prefix[2]= '1';
if(!(flag&1)) {
ret= fwrite(prefix,5,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(prefix,5,1,pktlog_fp);
if(ret<=0)
return(0);
}
if(npt==NULL) {
if(!(flag&1)) {
ret= fwrite(rpt,strlen(rpt),1,stdout);
if(ret<=0)
return(0);
ret= fwrite("\n",1,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(rpt,strlen(rpt),1,pktlog_fp);
if(ret<=0)
return(0);
ret= fwrite("\n",1,1,pktlog_fp);
if(ret<=0)
return(0);
}
break;
} else {
if(!(flag&1)) {
ret= fwrite(rpt,npt+1-rpt,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(rpt,npt+1-rpt,1,pktlog_fp);
if(ret<=0)
return(0);
}
}
rpt= npt+1;
}
if(!(flag&1))
fflush(stdout);
if(pktlog_fp!=NULL)
fflush(pktlog_fp);
return(1);
}
int Strcmp(const void *pt1, const void *pt2)
{
return(strcmp(*((char **) pt1), *((char **) pt2)));
}
int Sort_argv(int argc, char **argv, int flag)
{
if(argc<=0)
return(2);
qsort(argv,(size_t) argc,sizeof(char *),Strcmp);
return(1);
}
FILE *Afile_fopen(char *filename, char *mode, int flag)
/*
bit0= do not print error message on failure
bit6= write packeted error messages (see Write_to_channel())
*/
{
FILE *fp= NULL;
char errmsg[2*SfileadrL];
if(strcmp(filename,"-")==0) {
if(mode[0]=='a' || mode[0]=='w' ||
(mode[0]=='r' && mode[1]=='+') ||
(mode[0]=='r' && mode[1]=='b' && mode[2]=='+'))
fp= stdout;
else
fp= stdin;
} else if(strncmp(filename,"tcp:",4)==0){
sprintf(errmsg,"sorry - TCP/IP service isn't implemented yet.\n");
Write_to_channel(errmsg,2,!(flag&64));
} else if(strncmp(filename,"file:",5)==0){
fp= fopen(filename+5,mode);
} else {
fp= fopen(filename,mode);
}
if(fp==NULL){
if(!(flag&1)) {
sprintf(errmsg,"failed to open file '%s' in %s mode\n",filename,mode);
if(errno>0)
sprintf(errmsg+strlen(errmsg)," %s\n",strerror(errno));
Write_to_channel(errmsg,2,!(flag&64));
}
return(NULL);
}
return(fp);
}
/** Convert a text into a number of type double and multiply it by unit code
[kmgtpe] (2^10 to 2^60) or [s] (2048). (Also accepts capital letters.)
@param text Input like "42", "2k", "3.14m" or "-1g"
@param flag Bitfield for control purposes:
bit0= return -1 rathern than 0 on failure
@return The derived double value
*/
double Scanf_io_size(char *text, int flag)
/*
bit0= default value -1 rather than 0
*/
{
int c;
double ret= 0.0;
if(flag&1)
ret= -1.0;
if(text[0]==0)
return(ret);
sscanf(text,"%lf",&ret);
c= text[strlen(text)-1];
if(c=='k' || c=='K') ret*= 1024.0;
if(c=='m' || c=='M') ret*= 1024.0*1024.0;
if(c=='g' || c=='G') ret*= 1024.0*1024.0*1024.0;
if(c=='t' || c=='T') ret*= 1024.0*1024.0*1024.0*1024.0;
if(c=='p' || c=='P') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='e' || c=='E') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='s' || c=='S') ret*= 2048.0;
return(ret);
}
int Decode_date_input_format(struct tm *erg, char *text, int flag)
/* MMDDhhmm[[CC]YY][.ss]] */
{
int i,l,year;
time_t current_time;
struct tm *now;
current_time= time(0);
now= localtime(&current_time);
for(i=0;i<sizeof(struct tm);i++)
((char *) erg)[i]= ((char *) now)[i];
l= strlen(text);
for(i=0;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=8 && i!=10 && i!=12)
return(0);
if(text[i]==0)
goto decode;
if(text[i]!='.' || l!=15)
return(0);
i++;
if(text[i]<'0'||text[i]>'9')
return(0);
i++;
if(text[i]<'0'||text[i]>'9')
return(0);
decode:;
/* MMDDhhmm[[CC]YY][.ss]] */
i= 0;
erg->tm_mon= 10*(text[0]-'0')+text[1]-'0'-1;
erg->tm_mday= 10*(text[2]-'0')+text[3]-'0';
erg->tm_hour= 10*(text[4]-'0')+text[5]-'0';
erg->tm_min= 10*(text[6]-'0')+text[7]-'0';
erg->tm_sec= 0;
if(l==8)
return(1);
if(l>10){
year= 1000*(text[8]-'0')+100*(text[9]-'0')+10*(text[10]-'0')+(text[11]-'0');
}else{
year= 1900+10*(text[8]-'0')+(text[9]-'0');
if(year<1970)
year+= 100;
}
erg->tm_year= year-1900;
if(l<=12)
return(1);
erg->tm_sec= 10*(text[13]-'0')+text[14]-'0';
return(1);
}
int Decode_date_weekday(char *text, int flag)
{
int i;
static char days[][4]= {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", ""};
for(i= 0; days[i][0]!=0; i++)
if(strncmp(text,days[i],3)==0)
return(i);
if((strlen(text)==3 || (strlen(text)==4 && text[3]==',')) &&
isalpha(text[0]) && isalpha(text[1]) && isalpha(text[2]))
return(7);
return(-1);
}
int Decode_date_month(char *text, int flag)
{
int i;
static char months[][4]= {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
for(i= 0; months[i][0]!=0; i++)
if(strncmp(text,months[i],3)==0)
return(i);
return(-1);
}
/* @return -1=not a number, -2=not a day , 1 to 31 day of month */
int Decode_date_mday(char *text, int flag)
{
int ret, i;
for(i= 0; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(strlen(text)>2 || text[0]==0)
return(-2);
sscanf(text, "%d", &ret);
if(ret<=0 || ret>31)
return(-2);
return(ret);
}
int Decode_date_hms(char *text, struct tm *erg, int flag)
{
int i, hour= -1, minute= -1, second= 0;
for(i= 0; i<9; i+= 3) {
if(i==6&&text[i]==0)
break;
if(!isdigit(text[i]))
return(-1);
if(!isdigit(text[i+1]))
return(-1);
if(text[i+2]!=':' && !(text[i+2]==0 && i>=3))
return(-1);
if(i==0)
sscanf(text+i,"%d",&hour);
else if(i==3)
sscanf(text+i,"%d",&minute);
else
sscanf(text+i,"%d",&second);
}
if(hour<0 || hour>23 || minute<0 || minute>59 || second>59)
return(-1);
erg->tm_hour= hour;
erg->tm_min= minute;
erg->tm_sec= second;
return(1);
}
/* @return -1=not a number, -2=not a year , >=0 years AD */
int Decode_date_year(char *text, int flag)
{
int ret, i;
for(i= 0; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(strlen(text)!=4)
return(-2);
sscanf(text, "%d", &ret);
if(ret<0 || ret>3000)
return(-2);
return(ret);
}
int Decode_date_timezone(char *text, struct tm *erg, int flag)
{
int i;
static char tzs[][5]= {"GMT", "CET", "CEST", "0000", ""};
for(i= 0; tzs[i][0]!=0; i++)
if(strcmp(text,tzs[i])==0) {
/* ??? >>> what to do with timezone info ? Add to ->tm_hour ? */
return(1);
}
if(text[0]=='+' || text[0]=='-') {
for(i= 1; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(i!=5)
return(-1);
/* ??? >>> what to do with timezone info ? Add to ->tm_hour ? */
return(1);
} else {
for(i= 0; text[i]!=0; i++)
if(text[i]<'A' || text[i]>'Z')
return(-1);
if(i!=3 && i!=4)
return(-1);
return(2);
}
}
int Decode_date_output_format(struct tm *erg, char *text, int flag)
/* Thu Nov 8 09:07:50 CET 2007 */
/* Sat, 03 Nov 2007 08:58:30 +0100 */
/* Nov 7 23:24 */
{
int ret, i, argc= 0, seen_year= 0, seen_month= 0, seen_day= 0, seen_time= 0;
char **argv= NULL;
struct tm *now;
time_t timep;
memset(erg, 0, sizeof(*erg));
erg->tm_isdst= -1;
ret= Sfile_make_argv("xorriso", text, &argc, &argv, 0);
if(ret<=0)
goto ex;
for(i= 1; i<argc; i++) {
if(!seen_month) {
ret= Decode_date_month(argv[i], 0);
if(ret>=0) {
seen_month= 1;
erg->tm_mon= ret;
continue;
}
}
if(!seen_day) {
ret= Decode_date_mday(argv[i], 0);
if(ret>0) {
seen_day= 1;
erg->tm_mday= ret;
continue;
}
if(ret==-2) /* first pure number must be day of month */
{ret= 0; goto ex;}
}
if(!seen_time) {
ret= Decode_date_hms(argv[i], erg, 0);
if(ret>0) {
seen_time= 1;
continue;
}
}
if(!seen_year) {
ret= Decode_date_year(argv[i], 0);
if(ret>0) {
erg->tm_year= ret-1900;
seen_year= 1;
continue;
}
}
/* ignorants have to stay at the end of the loop */
ret= Decode_date_timezone(argv[i], erg, 0);
if(ret>=0)
continue;
ret= Decode_date_weekday(argv[i], 0);
if(ret>=0)
continue; /* ignore weekdays */
{ret= 0; goto ex;} /* unrecognizable component */
}
if(!(seen_day && seen_month))
{ret= 0; goto ex;}
if(!seen_year) { /* then use this year */
timep= time(NULL);
now= localtime(&timep);
erg->tm_year= now->tm_year;
}
ret= 1;
ex:
Sfile_make_argv("", "", &argc, &argv, 2); /* release storage */
return(ret);
}
int Decode_xorriso_timestamp(struct tm *erg, char *code, int flag)
/* 2007.11.07.225624 */
{
char buf[20];
int year,month,day,hour= 0,minute= 0,second= 0, i, l, mem;
memset(erg, 0, sizeof(*erg));
erg->tm_isdst= -1;
l= strlen(code);
if(l>17 || l<10)
return(0);
strcpy(buf, code);
for(i= 0; buf[i]!=0 && i<4; i++)
if(!isdigit(buf[i]))
return(0);
if(buf[4]!='.')
return(0);
buf[4]= 0;
sscanf(buf, "%d", &year);
if(year<1900 || year>3000)
return(0);
if(!(isdigit(buf[5]) && isdigit(buf[6]) && buf[7]=='.'))
return(0);
buf[7]= 0;
sscanf(buf+5, "%d", &month);
if(month<1 || month>12)
return(0);
if(!(isdigit(buf[8]) && isdigit(buf[9]) && (buf[10]=='.' || buf[10]==0)))
return(0);
buf[10]= 0;
sscanf(buf+8, "%d", &day);
if(day<1 || day>31)
return(0);
if(l==10)
goto done;
if(!(isdigit(buf[11]) && isdigit(buf[12]) &&
(isdigit(buf[13]) || buf[13]==0)))
return(0);
mem= buf[13];
buf[13]= 0;
sscanf(buf+11, "%d", &hour);
buf[13]= mem;
if(hour<0 || hour>23)
return(0);
if(l==13)
goto done;
if(!(isdigit(buf[13]) && isdigit(buf[14]) &&
(isdigit(buf[15]) || buf[15]==0)))
return(0);
mem= buf[15];
buf[15]= 0;
sscanf(buf+13, "%d", &minute);
buf[15]= mem;
if(minute<0 || minute>59)
return(0);
if(l==15)
goto done;
if(!(isdigit(buf[15]) && isdigit(buf[16]) && buf[17]==0))
return(0);
sscanf(buf+15, "%d", &second);
if(second<0 || second>59)
return(0);
done:;
erg->tm_year= year-1900;
erg->tm_mon= month-1;
erg->tm_mday= day;
erg->tm_hour= hour;
erg->tm_min= minute;
erg->tm_sec= second;
return(1);
}
time_t Decode_timestring(char *code, time_t *date, int flag)
{
char *cpt,scale_chr;
double value,seconds;
struct tm result_tm;
int seconds_valid= 0;
*date= 0;
cpt= code;
if(code[0]=='-' || code[0]=='+' || code[0]=='='){
if(code[1]==0)
return(0);
if(!isdigit(code[1]))
return(0);
value= -1;
if(code[0]=='=') {
seconds= 0;
sscanf(code+1,"%lf",&value);
} else {
seconds= time(NULL);
sscanf(code,"%lf",&value);
}
scale_chr= code[strlen(code)-1];
if(isalpha(scale_chr))
scale_chr= tolower(scale_chr);
if (scale_chr=='s') seconds+= 1.0*value;
else if(scale_chr=='h') seconds+= 3600.0*value;
else if(scale_chr=='d') seconds+= 86400.0*value;
else if(scale_chr=='w') seconds+= 86400.0*7.0*value;
else if(scale_chr=='m') seconds+= 86400.0*31.0*value;
else if(scale_chr=='y') seconds+= 86400.0*(365.25*value+1.0);
else seconds+= 1.0*value;
seconds_valid= 1;
goto completed;
} else if(Sfile_decode_datestr(&result_tm,code,0)>0) {
/* YYMMDD[.hhmm[ss]] */
result_tm.tm_isdst= -1;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_date_input_format(&result_tm,code,0)>0) {
/* MMDDhhmm[[CC]YY][.ss]] */
result_tm.tm_isdst= -1;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_xorriso_timestamp(&result_tm, code, 0)>0) {
/* 2007.11.07.225624 */
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_date_output_format(&result_tm, code, 0)>0) {
/* Thu Nov 8 09:07:50 CET 2007 */;
/* Sat, 03 Nov 2007 08:58:30 +0100 */;
/* Nov 7 23:24 */;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
}
return(0);
completed:;
if(!seconds_valid)
return(0);
*date= seconds;
return(1);
}
/* @param flag bit0=with year and seconds
bit1=timestamp format YYYY.MM.DD.hhmmss
*/
char *Ftimetxt(time_t t, char timetext[40], int flag)
{
char *rpt;
struct tm tms, *tmpt;
static char months[12][4]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
tmpt= localtime_r(&t, &tms);
rpt= timetext;
rpt[0]= 0;
if(tmpt==0)
sprintf(rpt+strlen(rpt), "%12.f", (double) t);
else if (flag&2)
sprintf(rpt+strlen(rpt), "%4.4d.%2.2d.%2.2d.%2.2d%2.2d%2.2d",
1900+tms.tm_year, tms.tm_mon, tms.tm_mday,
tms.tm_hour, tms.tm_min, tms.tm_sec);
else if (flag&1)
sprintf(rpt+strlen(rpt), "%2d %3s %4.4d %2.2d:%2.2d:%2.2d",
tms.tm_mday, months[tms.tm_mon], 1900+tms.tm_year,
tms.tm_hour, tms.tm_min, tms.tm_sec);
else if(time(NULL)-t < 180*86400 && time(NULL)-t >= 0)
sprintf(rpt+strlen(rpt), "%3s %2d %2.2d:%2.2d",
months[tms.tm_mon], tms.tm_mday, tms.tm_hour, tms.tm_min);
else
sprintf(rpt+strlen(rpt), "%3s %2d %4.4d",
months[tms.tm_mon], tms.tm_mday, 1900+tms.tm_year);
return(timetext);
}
/* @param flag bit0= single letters */
char *Ftypetxt(mode_t st_mode, int flag)
{
if(flag&1)
goto single_letters;
if(S_ISDIR(st_mode))
return("directory");
else if(S_ISREG(st_mode))
return("regular_file");
else if(S_ISLNK(st_mode))
return("symbolic_link");
else if(S_ISBLK(st_mode))
return("block_device");
else if(S_ISCHR(st_mode))
return("char_device");
else if(S_ISFIFO(st_mode))
return("name_pipe");
else if(S_ISSOCK(st_mode))
return("unix_socket");
return("unknown");
single_letters:;
if(S_ISDIR(st_mode))
return("d");
else if(S_ISREG(st_mode))
return("-");
else if(S_ISLNK(st_mode))
return("l");
else if(S_ISBLK(st_mode))
return("b");
else if(S_ISCHR(st_mode))
return("c");
else if(S_ISFIFO(st_mode))
return("p");
else if(S_ISSOCK(st_mode))
return("s");
return("?");
}
/* ------------------------------------------------------------------------ */
#ifndef Xorriso_sregex_externaL
#ifndef Smem_malloC
#define Smem_malloC malloc
#endif
#ifndef Smem_freE
#define Smem_freE free
#endif
int Sregex_string_cut(char **handle, char *text, int len, int flag)
/*
bit0= append (text!=NULL)
*/
{
int l=0;
char *old_handle;
if((flag&1)&&*handle!=NULL)
l+= strlen(*handle);
old_handle= *handle;
if(text!=NULL) {
l+= len;
*handle= TSOB_FELD(char,l+1);
if(*handle==NULL) {
*handle= old_handle;
return(0);
}
if((flag&1) && old_handle!=NULL)
strcpy(*handle,old_handle);
else
(*handle)[0]= 0;
if(len>0)
strncat(*handle,text,len);
} else {
*handle= NULL;
}
if(old_handle!=NULL)
Smem_freE(old_handle);
return(1);
}
int Sregex_string(char **handle, char *text, int flag)
/*
bit0= append (text!=NULL)
*/
{
int ret,l=0;
if(text!=NULL)
l= strlen(text);
/* #define Sregex_looking_for_contenT 1 */
#ifdef Sregex_looking_for_contenT
/* a debugging point if a certain text content has to be caught */
if(text!=NULL)
if(strcmp(text,"clear")==0)
ret= 0;
#endif
ret= Sregex_string_cut(handle,text,l,flag&1);
return(ret);
}
#endif /* Xorriso_sregex_externaL */
/* @param flag bit0= append to out_text rather than overwrite it
*/
char *Text_shellsafe(char *in_text, char *out_text, int flag)
{
int l,i,ol= 0,w=0;
if(flag&1)
ol= w= strlen(out_text);
/* enclose everything by hard quotes */
l= strlen(in_text);
out_text[w++]= '\'';
for(i=0;i<l;i++){
if(in_text[i]=='\''){
if(w+7>5*SfileadrL+ol)
goto overflow;
/* escape hard quote within the text */
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
} else {
if(w+3>5*SfileadrL) {
overflow:;
strncpy(out_text, "'xorriso: TEXT MUCH TOO LONG ... ",33);
break;
}
out_text[w++]= in_text[i];
}
}
out_text[w++]= '\'';
out_text[w++]= 0;
return(out_text);
}
#ifndef Xorriso_fileliste_externaL
/* ??? ts A71006 : Is this compatible with mkisofs pathspecs ?
I dimly remember so */
int Fileliste__target_source_limit(char *line, char sep, char **limit_pt,
int flag)
{
char *npt;
for(npt= line;*npt!=0;npt++) {
if(*npt=='\\') {
if(*(npt+1)!=0)
npt++;
continue;
}
if(*npt=='=')
break;
}
if(*npt==0)
npt= NULL;
(*limit_pt)= npt;
return(npt!=NULL);
}
#endif /* ! Xorriso_fileliste_externaL */
/* ------------------------------------------------------------------------ */
/* DirseQ : crawl along a directory's content list */
static int Dirseq_buffer_sizE= 100;
struct DirseQ {
char adr[SfileadrL];
DIR *dirpt;
int count;
char **buffer;
int buffer_size;
int buffer_fill;
int buffer_rpt;
struct DirseQ *next;
};
int Dirseq_destroy(struct DirseQ **o, int flag);
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
int max_replies, int flag);
int Dirseq_new(struct DirseQ **o, char *adr, int flag)
/*
bit0= with non-fatal errors do not complain about failed opendir()
*/
{
int ret,i,severe_error;
struct DirseQ *m;
m= *o= TSOB_FELD(struct DirseQ,1);
if(m==NULL)
return(-1);
m->adr[0]= 0;
m->dirpt= NULL;
m->count= 0;
m->buffer= NULL;
m->buffer_size= 0;
m->buffer_fill= 0;
m->buffer_rpt= 0;
m->next= NULL;
if(Sfile_str(m->adr, adr, 0)<=0)
{ret= 0; goto failed;}
m->buffer= TSOB_FELD(char *,Dirseq_buffer_sizE);
if(m->buffer==NULL)
{ret= -1; goto failed;}
m->buffer_size= Dirseq_buffer_sizE;
for(i= 0;i<m->buffer_size;i++)
m->buffer[i]= NULL;
if(adr[0]==0)
m->dirpt= opendir(".");
else
m->dirpt= opendir(adr);
if(m->dirpt==NULL) {
severe_error= (errno && errno!=ENOENT && errno!=EACCES && errno!=ENOTDIR);
if(severe_error || !(flag&1))
fprintf(stderr,"opendir(%s) failed : %s\n",adr,strerror(errno));
ret= -severe_error;
goto failed;
}
return(1);
failed:;
Dirseq_destroy(o,0);
return(ret);
}
int Dirseq_destroy(struct DirseQ **o, int flag)
{
int i;
if(*o==NULL)
return(0);
if((*o)->dirpt!=NULL)
closedir((*o)->dirpt);
if((*o)->buffer!=NULL) {
for(i=0;i<(*o)->buffer_size;i++)
if((*o)->buffer[i]!=NULL)
free((*o)->buffer[i]);
free((char *) (*o)->buffer);
}
free((char *) *o);
(*o)= NULL;
return(1);
}
int Dirseq_set_next(struct DirseQ *o, struct DirseQ *next, int flag)
{
o->next= next;
return(1);
}
int Dirseq_get_next(struct DirseQ *o, struct DirseQ **next, int flag)
{
*next= o->next;
return(1);
}
int Dirseq_get_adr(struct DirseQ *o, char **adrpt, int flag)
{
*adrpt= o->adr;
return(1);
}
int Dirseq_rewind(struct DirseQ *o, int flag)
{
rewinddir(o->dirpt);
return(1);
}
int Dirseq_next_adr(struct DirseQ *o, char reply[SfileadrL], int flag)
/*
flag:
bit0= permission to use buffer
bit1= do not increment counter
bit2= ignore buffer in any case
bit3= do not exclude '.' and '..'
bit4= sort buffer
bit5= sort only incomplete last buffer
return:
<0 error
0= no more entries available
1= ok, reply is valid
*/
{
int ret;
struct dirent *entry;
char *name;
static int override_flag_0= 0,override_flag_1= 32;
flag= (flag&~override_flag_0)|override_flag_1;
if((flag&1) && o->buffer_rpt>=o->buffer_fill) {
/* permission to buffer and buffer empty : load a buffer */
ret= Dirseq_next_adrblock(o,o->buffer,&(o->buffer_fill),
o->buffer_size,2|4|(flag&16));
if(ret<=0)
return(ret);
o->buffer_rpt= 0;
if((flag&32) && o->buffer_fill<o->buffer_size && o->buffer_fill>0)
Sort_argv(o->buffer_fill,o->buffer,0);
}
if(o->buffer_rpt<o->buffer_fill && !(flag&4)) {
ret= Sfile_str(reply,o->buffer[o->buffer_rpt],0);
Sregex_string(&(o->buffer[o->buffer_rpt]),NULL,0);
if(ret<=0)
return(-1);
(o->buffer_rpt)++;
if(!(flag&2))
o->count++;
return(1);
}
do {
entry= readdir(o->dirpt);
if(entry==NULL) {
/* >>> how to distinguish error from EOF , do i need a (FILE *) ? */
return(0);
}
if(strlen(entry->d_name)>=SfileadrL) {
fprintf(stderr,"--- oversized directory entry (number %d) :\n %s",
o->count+1,entry->d_name);
return(-1);
}
name= entry->d_name;
if(flag&8)
break;
/* skip "." and ".." */
} while(name[0]=='.' && ((name[1]=='.' && name[2]==0) || name[1]==0));
if(Sfile_str(reply,name,0)<=0)
return(-1);
if(!(flag&2))
o->count++;
return(1);
}
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
int max_replies, int flag)
/* @param replies A vector of Sregex_string pointers */
/*
flag:
bit0= permission to use buffer
bit1= do not increment counter
bit2= ignore buffer in any case
bit4= sort replies
return:
<0 error
0= no more entries available
1= ok, reply is valid
*/
{
int i,ret;
char reply[SfileadrL];
*reply_count= 0;
for(i=0;i<max_replies;i++) {
ret= Dirseq_next_adr(o,reply,flag&(1|2|4));
if(ret<0)
return(ret);
if(ret==0)
break;
if(Sregex_string(&(replies[i]),reply,0)<=0)
return(-1);
(*reply_count)++;
}
if((*reply_count)==0)
return(0);
if(flag&16)
Sort_argv(*reply_count,replies,0);
return(1);
}
#ifndef Xorriso_sregex_externaL
/* ---------------------------------- LstrinG --------------------------- */
/*
@param flag Bitfield for control purposes
bit0= insert before link rather than after it
bit1= do not copy data (e.g. because *data is invalid)
*/
int Lstring_new_binary(struct LstrinG **lstring, char *data, int data_len,
struct LstrinG *link, int flag)
{
int ret;
struct LstrinG *s;
s= TSOB_FELD(struct LstrinG,1);
if(s==NULL)
return(-1);
s->text= NULL;
s->next= s->prev= NULL;
if(data_len<=0)
{ret= -1; goto failed;}
s->text= Smem_malloC(data_len);
if(s->text==NULL)
{ret= -1; goto failed;}
if(!(flag&2))
memcpy(s->text,data,data_len);
if(link==NULL) {
;
} else if(flag&1) {
s->next= link;
s->prev= link->prev;
if(link->prev!=NULL)
link->prev->next= s;
link->prev= s;
} else {
s->prev= link;
s->next= link->next;
if(link->next!=NULL)
link->next->prev= s;
link->next= s;
}
*lstring= s;
return(1);
failed:;
*lstring= s;
Lstring_destroy(lstring,0);
return(-1);
}
/*
@param flag Bitfield for control purposes
bit0= insert before link rather than after it
*/
int Lstring_new(struct LstrinG **lstring, char *text, struct LstrinG *link,
int flag)
{
int ret;
ret= Lstring_new_binary(lstring,text,strlen(text)+1,link,flag&1);
return(ret);
}
/*
@param flag Bitfield for control purposes
bit0= do not set *lstring to NULL
*/
int Lstring_destroy(struct LstrinG **lstring, int flag)
{
struct LstrinG *s;
s= *lstring;
if(s==NULL)
return(0);
if(s->prev!=NULL)
s->prev->next= s->next;
if(s->next!=NULL)
s->next->prev= s->prev;
if(s->text!=NULL)
Smem_freE(s->text);
Smem_freE((char *) s);
if(!(flag&1))
*lstring= NULL;
return(1);
}
int Lstring_destroy_all(struct LstrinG **lstring, int flag)
{
struct LstrinG *s,*next;
if((*lstring)==NULL)
return(0);
for(s= *lstring; s->prev!=NULL; s= s->prev);
for(;s!=NULL;s= next){
next= s->next;
Lstring_destroy(&s,0);
}
*lstring= NULL;
return(1);
}
int Lstring_append_binary(struct LstrinG **entry, char *data, int data_len,
int flag)
{
struct LstrinG *target= NULL,*newby;
if(*entry!=NULL)
for(target= *entry; target->next!=NULL; target= target->next);
if(Lstring_new_binary(&newby, data, data_len, target, 0)<=0)
return(-1);
if(*entry==NULL)
*entry= newby;
return(1);
}
#endif /* Xorriso_sregex_externaL */
/* ------------------------------ LinkiteM -------------------------------- */
struct LinkiteM {
char *link_path;
dev_t target_dev;
ino_t target_ino;
int link_count;
struct LinkiteM *next;
};
int Linkitem_destroy(struct LinkiteM **o, int flag);
int Linkitem_new(struct LinkiteM **o, char *link_path, dev_t target_dev,
ino_t target_ino, struct LinkiteM *next, int flag)
{
struct LinkiteM *m;
m= *o= TSOB_FELD(struct LinkiteM,1);
if(m==NULL)
return(-1);
m->target_dev= target_dev;
m->target_ino= target_ino;
m->next= next;
m->link_count= 1;
if(next!=NULL)
m->link_count= m->next->link_count+1;
m->link_path= strdup(link_path);
if(m->link_path==NULL)
goto failed;
return(1);
failed:;
Linkitem_destroy(o, 0);
return(-1);
}
int Linkitem_destroy(struct LinkiteM **o, int flag)
{
if((*o)==NULL)
return(0);
if((*o)->link_path!=NULL)
free((*o)->link_path);
free((char *) (*o));
*o= NULL;
return(1);
}
int Linkitem_reset_stack(struct LinkiteM **o, struct LinkiteM *to, int flag)
{
struct LinkiteM *m, *m_next= NULL;
/* Prevent memory corruption */
for(m= *o; m!=to; m= m->next)
if(m==NULL) { /* this may actually not happen */
*o= to;
return(-1);
}
for(m= *o; m!=to; m= m_next) {
m_next= m->next;
Linkitem_destroy(&m, 0);
}
*o= to;
return(1);
}
int Linkitem_find(struct LinkiteM *stack, dev_t target_dev, ino_t target_ino,
struct LinkiteM **result, int flag)
{
struct LinkiteM *m;
for(m= stack; m!=NULL; m= m->next) {
if(target_dev == m->target_dev && target_ino == m->target_ino) {
*result= m;
return(1);
}
}
return(0);
}
/* ------------------------------- FindjoB -------------------------------- */
struct FindjoB {
char *start_path;
char *name_expr;
regex_t name_re;
regmatch_t name_match;
/* b = blockdev
c = chardev
d = directory
p = fifo
f = reg
- = reg
s = socket
m = subordinate mountpoint (does never match find start directory)
X = other
0x0 = test inactive
*/
char file_type;
/* 0= echo
1= rm (also rmdir)
2= rm_r
>>> 3= mv target
4= chown user
5= chgrp group
6= chmod mode_and mode_or
7= alter_date type date
8= lsdl
9= chown_r user
10= chgrp_r group
11= chmod_r mode_and mode_or
12= alter_date_r type date
13= find
14= compare disk_equivalent_of_start_path
15= in_iso iso_rr_equivalent_of_start_path
16= not_in_iso iso_rr_equiv
17= update disk_equiv
18= add_missing iso_rr_equiv
19= empty_iso_dir iso_rr_equiv
20= is_full_in_iso iso_rr_equiv
*/
int action;
char *target;
uid_t user;
gid_t group;
mode_t mode_and, mode_or;
int type; /* see Xorriso_set_time flag */
time_t date;
struct FindjoB *subjob;
};
int Findjob_destroy(struct FindjoB **job, int flag);
int Findjob_new(struct FindjoB **o, char *start_path, int flag)
{
struct FindjoB *m;
m= *o= TSOB_FELD(struct FindjoB,1);
if(m==NULL)
return(-1);
m->start_path= NULL;
m->name_expr= NULL;
m->file_type= 0;
m->action= 0; /* print */
m->target= NULL; /* a mere pointer, not managed memory */
m->user= 0;
m->group= 0;
m->type= 0;
m->date= 0;
m->subjob= NULL;
m->start_path= strdup(start_path);
if(m->start_path==NULL)
goto failed;
return(1);
failed:;
Findjob_destroy(o, 0);
return(-1);
}
int Findjob_destroy(struct FindjoB **o, int flag)
{
struct FindjoB *m;
m= *o;
if(m==NULL)
return(0);
if(m->start_path!=NULL)
free(m->start_path);
if(m->name_expr!=NULL) {
regfree(&(m->name_re));
free(m->name_expr);
}
Findjob_destroy(&(m->subjob), 0);
free((char *) m);
*o= NULL;
return(1);
}
int Findjob_set_start_path(struct FindjoB *o, char *start_path, int flag)
{
if(o->start_path!=NULL)
free(o->start_path);
if(start_path!=NULL) {
o->start_path= strdup(start_path);
if(o->start_path==NULL)
return(-1);
} else
o->start_path= NULL;
return(1);
}
int Findjob_get_start_path(struct FindjoB *o, char **start_path, int flag)
{
*start_path= o->start_path;
return(1);
}
int Findjob_set_name_expr(struct FindjoB *o, char *name_expr, int flag)
{
char regexpr[2*SfileadrL+2];
if(o->name_expr!=NULL) {
regfree(&(o->name_re));
free(o->name_expr);
o->name_expr= NULL;
}
if(strlen(name_expr)>=SfileadrL)
return(0);
o->name_expr= strdup(name_expr);
if(o->name_expr==NULL)
return(-1);
Xorriso__bourne_to_reg(name_expr, regexpr, 0);
if(regcomp(&(o->name_re), regexpr, 0)!=0)
return(0);
return(1);
}
int Findjob_set_file_type(struct FindjoB *o, char file_type, int flag)
{
static char known[]= {"bcdpf-lsmX"};
if(file_type!=0)
if(strchr(known, file_type)==NULL)
return(0);
o->file_type= file_type;
return(1);
}
/* @return 0=no match , 1=match , <0 = error
*/
int Findjob_test(struct FindjoB *o, char *name,
struct stat *boss_stbuf, struct stat *stbuf,
int depth, int flag)
{
int ret;
if(o->name_expr!=NULL) {
ret= regexec(&(o->name_re),name,1,&(o->name_match),0);
if(ret!=0)
return(0);
}
if(o->file_type!=0) {
if(S_ISBLK(stbuf->st_mode)) {
if(o->file_type!='b')
return(0);
} else if(S_ISCHR(stbuf->st_mode)) {
if(o->file_type!='c')
return(0);
} else if(S_ISDIR(stbuf->st_mode)) {
if(o->file_type=='m') {
if(boss_stbuf==NULL)
return(0);
if(boss_stbuf->st_dev == stbuf->st_dev)
return(0);
} else if(o->file_type!='d')
return(0);
} else if(S_ISFIFO(stbuf->st_mode)) {
if(o->file_type!='p')
return(0);
} else if(S_ISREG(stbuf->st_mode)) {
if(o->file_type!='f' && o->file_type!='-')
return(0);
} else if(((stbuf->st_mode)&S_IFMT)==S_IFLNK) {
if(o->file_type!='l')
return(0);
} else if(((stbuf->st_mode)&S_IFMT)==S_IFSOCK) {
if(o->file_type!='s')
return(0);
} else {
if(o->file_type!='X')
return(0);
}
}
/* ??? >>> more tests to come ?*/;
return(1);
}
int Findjob_get_action(struct FindjoB *o, int flag)
{
return(o->action);
}
/* @return <0 error, >=0 see above struct FindjoB.action
*/
int Findjob_get_action_parms(struct FindjoB *o, char **target,
uid_t *user, gid_t *group,
mode_t *mode_and, mode_t *mode_or,
int *type, time_t *date, struct FindjoB **subjob,
int flag)
{
*target= o->target;
*user= o->user;
*group= o->group;
*mode_and= o->mode_and;
*mode_or= o->mode_or;
*type= o->type;
*date= o->date;
*subjob= o->subjob;
return(o->action);
}
int Findjob_set_action_target(struct FindjoB *o, int action, char *target,
int flag)
{
o->action= action;
o->target= target;
return(1);
}
/* @param flag bit0= recursive
*/
int Findjob_set_action_chown(struct FindjoB *o, uid_t user,int flag)
{
int ret;
if(flag&1) {
o->action= 0;
Findjob_destroy(&(o->subjob), 0);
ret= Findjob_new(&(o->subjob), "", 0);
if(ret<=0)
return(-1);
Findjob_set_action_chown(o->subjob, user, 0);
o->action= 9;
} else {
o->action= 4;
o->user= user;
}
return(1);
}
/* @param flag bit0= recursive
*/
int Findjob_set_action_chgrp(struct FindjoB *o, gid_t group, int flag)
{
int ret;
if(flag&1) {
o->action= 0;
Findjob_destroy(&(o->subjob), 0);
ret= Findjob_new(&(o->subjob), "", 0);
if(ret<=0)
return(-1);
Findjob_set_action_chgrp(o->subjob, group, 0);
o->action= 10;
} else {
o->action= 5;
o->group= group;
}
return(1);
}
/* @param flag bit0= recursive
*/
int Findjob_set_action_chmod(struct FindjoB *o,
mode_t mode_and, mode_t mode_or, int flag)
{
int ret;
if(flag&1) {
o->action= 0;
Findjob_destroy(&(o->subjob), 0);
ret= Findjob_new(&(o->subjob), "", 0);
if(ret<=0)
return(-1);
Findjob_set_action_chmod(o->subjob, mode_and, mode_or, 0);
o->action= 11;
} else {
o->action= 6;
o->mode_and= mode_and;
o->mode_or= mode_or;
}
return(1);
}
/* @param flag bit0= recursive
*/
int Findjob_set_action_ad(struct FindjoB *o, int type, time_t date, int flag)
{
int ret;
if(flag&1) {
o->action= 0;
Findjob_destroy(&(o->subjob), 0);
ret= Findjob_new(&(o->subjob), "", 0);
if(ret<=0)
return(-1);
Findjob_set_action_ad(o->subjob, type, date, 0);
o->action= 12;
} else {
o->action= 7;
o->type= type;
o->date= date;
}
return(1);
}
int Findjob_set_action_subjob(struct FindjoB *o, int action,
struct FindjoB *subjob, int flag)
{
o->action= action;
Findjob_destroy(&(o->subjob), 0);
o->subjob= subjob;
return(1);
}
/* ---------------------------- SplitparT ------------------------- */
struct SplitparT {
char *name;
int partno;
int total_parts;
off_t offset;
off_t bytes;
off_t total_bytes;
};
int Splitparts_new(struct SplitparT **o, int count, int flag)
{
int i;
(*o)= TSOB_FELD(struct SplitparT, count);
if((*o)==NULL)
return(-1);
for(i= 0; i<count; i++) {
(*o)[i].name= NULL;
(*o)[i].partno= 0;
(*o)[i].total_parts= 0;
(*o)[i].offset= 0;
(*o)[i].bytes= 0;
(*o)[i].total_bytes= 0;
}
return(1);
}
int Splitparts_destroy(struct SplitparT **o, int count, int flag)
{
int i;
if((*o)==NULL)
return(0);
for(i= 0; i<count; i++) {
if((*o)[i].name!=NULL)
free((*o)[i].name);
}
free(*o);
*o= NULL;
return(1);
}
int Splitparts_set(struct SplitparT *o, int idx,
char *name, int partno, int total_parts,
off_t offset, off_t bytes, off_t total_bytes, int flag)
{
if(o[idx].name!=NULL)
free(o[idx].name);
o[idx].name= strdup(name);
if(o[idx].name==NULL)
return(-1);
o[idx].partno= partno;
o[idx].total_parts= total_parts;
o[idx].offset= offset;
o[idx].bytes= bytes;
o[idx].total_bytes= total_bytes;
return(1);
}
int Splitparts_get(struct SplitparT *o, int idx, char **name, int *partno,
int *total_parts, off_t *offset, off_t *bytes,
off_t *total_bytes, int flag)
{
*name= o[idx].name;
*partno= o[idx].partno;
*total_parts= o[idx].total_parts;
*offset= o[idx].offset;
*bytes= o[idx].bytes;
*total_bytes= o[idx].total_bytes;
return(1);
}
int Splitpart__read_next_num(char *base_pt, char **next_pt, off_t *num,
int flag)
{
char *cpt, *ept, scale[4];
*num= 0;
for(cpt= base_pt; *cpt!=0 && !isdigit(*cpt); cpt++);
if(*cpt==0)
return(0);
for(ept= cpt; *ept!=0 && isdigit(*ept); ept++)
*num= (*num)*10+(*ept)-'0';
scale[0]= '1';
scale[1]= *ept;
scale[2]= 0;
*num *= (off_t) Scanf_io_size(scale, 0);
if(*ept!=0)
ept++;
*next_pt= ept;
return(1);
}
int Splitpart__parse(char *name, int *partno, int *total_parts,
off_t *offset, off_t *bytes, off_t *total_bytes, int flag)
{
int ret;
off_t num;
char *cpt, *ept;
cpt= name;
ret= Splitpart__read_next_num(cpt, &ept, &num, 0);
if(ret<=0)
return(ret);
*partno= num;
cpt= ept;
ret= Splitpart__read_next_num(cpt, &ept, &num, 0);
if(ret<=0)
return(ret);
*total_parts= num;
cpt= ept;
ret= Splitpart__read_next_num(cpt, &ept, offset, 0);
if(ret<=0)
return(ret);
cpt= ept;
ret= Splitpart__read_next_num(cpt, &ept, bytes, 0);
if(ret<=0)
return(ret);
cpt= ept;
ret= Splitpart__read_next_num(cpt, &ept, total_bytes, 0);
if(ret<=0)
return(ret);
return(1);
}
int Splitpart__compose(char *adr, int partno, int total_parts,
off_t offset, off_t bytes, off_t total_bytes, int flag)
{
sprintf(adr, "part_%d_of_%d_at_", partno, total_parts);
if((offset % (1024*1024))==0 && offset>0) {
Sfile_off_t_text(adr+strlen(adr), offset / (1024*1024), 0);
strcat(adr, "m");
} else
Sfile_off_t_text(adr+strlen(adr), offset, 0);
strcat(adr, "_with_");
if((bytes % (1024*1024))==0) {
Sfile_off_t_text(adr+strlen(adr), bytes / (1024*1024), 0);
strcat(adr, "m");
} else
Sfile_off_t_text(adr+strlen(adr), bytes, 0);
strcat(adr, "_of_");
Sfile_off_t_text(adr+strlen(adr), total_bytes, 0);
return(1);
}
int Splitparts_cmp(const void *v1, const void *v2)
{
struct SplitparT *p1, *p2;
p1= (struct SplitparT *) v1;
p2= (struct SplitparT *) v2;
if(p1->partno>p2->partno)
return(1);
if(p1->partno<p2->partno)
return(-1);
if(p1->offset>p2->offset)
return(1);
if(p1->offset<p2->offset)
return(-1);
return(0);
}
int Splitparts_sort(struct SplitparT *o, int count, int flag)
{
qsort(o, (size_t) count, sizeof(struct SplitparT), Splitparts_cmp);
return(1);
}
/* ---------------------------- End SplitparT ------------------------- */
/* ------------------------------ ExclusionS ------------------------------ */
struct ExclusionS {
/* Absolute input patterns which lead to not_paths */
struct LstrinG *not_paths_descr;
/* Actually banned absolute paths */
struct LstrinG *not_paths;
/* Input patterns which lead to not_leafs */
struct LstrinG *not_leafs_descr;
/* Compiled not_leaf patterns. Caution: not char[] but regex_t */
struct LstrinG *not_leafs;
};
int Exclusions_new(struct ExclusionS **o, int flag)
{
struct ExclusionS *m;
m= *o= TSOB_FELD(struct ExclusionS, 1);
if(m==NULL)
return(-1);
m->not_paths_descr= NULL;
m->not_paths= NULL;
m->not_leafs_descr= NULL;
m->not_leafs= NULL;
return(1);
}
int Exclusions_destroy(struct ExclusionS **o, int flag)
{
struct LstrinG *s,*next;
if((*o)==NULL)
return(0);
Lstring_destroy_all(&((*o)->not_paths_descr), 0);
Lstring_destroy_all(&((*o)->not_paths), 0);
Lstring_destroy_all(&((*o)->not_leafs_descr), 0);
for(s= (*o)->not_leafs; s!=NULL; s= next){
next= s->next;
regfree((regex_t *) s->text);
Lstring_destroy(&s, 0);
}
(*o)= NULL;
return(1);
}
int Exclusions_add_not_paths(struct ExclusionS *o, int descrc, char **descrs,
int pathc, char **paths, int flag)
{
struct LstrinG *s, *new_s;
int i, ret;
s= NULL;
if(o->not_paths_descr!=NULL)
for(s= o->not_paths_descr; s->next!=NULL; s= s->next);
for(i= 0; i<descrc; i++) {
ret= Lstring_new(&new_s, descrs[i], s, 0)