|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include "xmalloc.h"
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <pwd.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <time.h>
|
|
Packit |
8f70b4 |
#include <ctype.h>
|
|
Packit |
8f70b4 |
#include <sys/ioctl.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <pwd.h>
|
|
Packit |
8f70b4 |
#include <sys/socket.h>
|
|
Packit |
8f70b4 |
#include <netinet/in.h>
|
|
Packit |
8f70b4 |
#include <arpa/inet.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef HAVE_TERMIOS_H
|
|
Packit |
8f70b4 |
#include <termios.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef TIME_WITH_SYS_TIME
|
|
Packit |
8f70b4 |
# include <sys/time.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if LIBIDN2
|
|
Packit |
8f70b4 |
# include <idn2.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef HAVE_DLFCN_H
|
|
Packit |
8f70b4 |
# include <dlfcn.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include "regex.h"
|
|
Packit |
8f70b4 |
#include "human.h"
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "ProcWait.h"
|
|
Packit |
8f70b4 |
#include "SignalHook.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include <mbswidth.h>
|
|
Packit |
8f70b4 |
#include "strftime.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *dir_file(const char *dir,const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(dir==0 || dir[0]==0)
|
|
Packit |
8f70b4 |
return file?file:dir;
|
|
Packit |
8f70b4 |
if(file==0 || file[0]==0)
|
|
Packit |
8f70b4 |
return dir;
|
|
Packit |
8f70b4 |
if(file[0]=='/')
|
|
Packit |
8f70b4 |
return file;
|
|
Packit |
8f70b4 |
if(file[0]=='.' && file[1]=='/')
|
|
Packit |
8f70b4 |
file+=2;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& buf=xstring::get_tmp();
|
|
Packit |
8f70b4 |
size_t len=strlen(dir);
|
|
Packit |
8f70b4 |
if(len==0)
|
|
Packit |
8f70b4 |
return buf.set(file);
|
|
Packit |
8f70b4 |
if(dir[len-1]=='/')
|
|
Packit |
8f70b4 |
return buf.vset(dir,file,NULL);
|
|
Packit |
8f70b4 |
return buf.vset(dir,"/",file,NULL);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *url_file(const char *url,const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static xstring buf;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(buf && url==buf) // it is possible to url_file(url_file(url,dir),file)
|
|
Packit |
8f70b4 |
url=alloca_strdup(url);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!url || url[0]==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf.set(file?file:"");
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ParsedURL u(url);
|
|
Packit |
8f70b4 |
if(!u.proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf.set(dir_file(url,file));
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(file && file[0]=='~')
|
|
Packit |
8f70b4 |
u.path.set(file);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
u.path.set(dir_file(u.path,file));
|
|
Packit |
8f70b4 |
buf.truncate();
|
|
Packit |
8f70b4 |
return u.CombineTo(buf);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *output_file_name(const char *src,const char *dst,bool dst_local,
|
|
Packit |
8f70b4 |
const char *dst_base,bool make_dirs)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool dst_is_dir=false;
|
|
Packit |
8f70b4 |
if(dst)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(dst_base)
|
|
Packit |
8f70b4 |
dst=url_file(dst_base,dst);
|
|
Packit |
8f70b4 |
ParsedURL u_dst(dst,true);
|
|
Packit |
8f70b4 |
if(u_dst.proto)
|
|
Packit |
8f70b4 |
dst_local=false;
|
|
Packit |
8f70b4 |
if(dst_local)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dst=expand_home_relative(dst);
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(dst,&st)!=-1 && S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
dst_is_dir=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=xstrlen(u_dst.path);
|
|
Packit |
8f70b4 |
if(len>0 && u_dst.path[len-1]=='/')
|
|
Packit |
8f70b4 |
dst_is_dir=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!dst_is_dir)
|
|
Packit |
8f70b4 |
return dst;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL u_src(src,true);
|
|
Packit |
8f70b4 |
if(u_src.proto)
|
|
Packit |
8f70b4 |
src=u_src.path;
|
|
Packit |
8f70b4 |
if(!src)
|
|
Packit |
8f70b4 |
return ""; // there will be error anyway.
|
|
Packit |
8f70b4 |
const char *base=basename_ptr(src);
|
|
Packit |
8f70b4 |
if(make_dirs && !dst)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
base=src;
|
|
Packit |
8f70b4 |
if(base[0]=='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
base=strchr(base,'/');
|
|
Packit |
8f70b4 |
if(!base)
|
|
Packit |
8f70b4 |
base="";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
while(*base=='/')
|
|
Packit |
8f70b4 |
base++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return url_file(dst?dst:dst_base,base);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *basename_ptr(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *s1=s+strlen(s);
|
|
Packit |
8f70b4 |
while(s1>s && s1[-1]=='/')
|
|
Packit |
8f70b4 |
s1--;
|
|
Packit |
8f70b4 |
while(s1>s && s1[-1]!='/')
|
|
Packit |
8f70b4 |
s1--;
|
|
Packit |
8f70b4 |
return s1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *expand_home_relative(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s[0]!='~')
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *home=0;
|
|
Packit |
8f70b4 |
const char *sl=strchr(s+1,'/');
|
|
Packit |
8f70b4 |
static xstring ret_path;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(s[1]==0 || s[1]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
home=get_home();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// extract user name and find the home
|
|
Packit |
8f70b4 |
int name_len=(sl?sl-s-1:strlen(s+1));
|
|
Packit |
8f70b4 |
struct passwd *pw=getpwnam(xstring::get_tmp(s+1,name_len));
|
|
Packit |
8f70b4 |
if(pw)
|
|
Packit |
8f70b4 |
home=pw->pw_dir;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(home==0)
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(sl)
|
|
Packit |
8f70b4 |
return ret_path.vset(home,sl,NULL);
|
|
Packit |
8f70b4 |
return home;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int create_directories(char *path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *sl=path;
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(access(path,0)==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sl=strchr(sl,'/');
|
|
Packit |
8f70b4 |
if(sl==path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sl++;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(sl)
|
|
Packit |
8f70b4 |
*sl=0;
|
|
Packit |
8f70b4 |
if(access(path,0)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
res=mkdir(path,0777);
|
|
Packit |
8f70b4 |
if(res==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(errno!=EEXIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fprintf(stderr,"mkdir(%s): %s\n",path,strerror(errno));
|
|
Packit |
8f70b4 |
if(sl)
|
|
Packit |
8f70b4 |
*sl='/';
|
|
Packit |
8f70b4 |
return(-1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(sl)
|
|
Packit |
8f70b4 |
*sl++='/';
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void truncate_file_tree(const char *dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
pid_t pid;
|
|
Packit |
8f70b4 |
switch(pid=fork())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(0): // child
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGINT);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGTSTP);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGQUIT);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGHUP);
|
|
Packit |
8f70b4 |
execlp("rm","rm","-rf",dir,(char*)NULL);
|
|
Packit |
8f70b4 |
perror("execlp(rm)");
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
_exit(1);
|
|
Packit |
8f70b4 |
case(-1): // error
|
|
Packit |
8f70b4 |
perror("fork()");
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
default: // parent
|
|
Packit |
8f70b4 |
(new ProcWait(pid))->Auto(); // don't wait for termination
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int fd_width(int fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fd == -1) return -1;
|
|
Packit |
8f70b4 |
if(!isatty(fd)) return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef TIOCGWINSZ
|
|
Packit |
8f70b4 |
struct winsize sz;
|
|
Packit |
8f70b4 |
sz.ws_col=sz.ws_row=0;
|
|
Packit |
8f70b4 |
ioctl(fd,TIOCGWINSZ,&sz);
|
|
Packit |
8f70b4 |
if(sz.ws_col==0)
|
|
Packit |
8f70b4 |
sz.ws_col=80;
|
|
Packit |
8f70b4 |
return(sz.ws_col);
|
|
Packit |
8f70b4 |
#else /* !TIOCGWINSZ */
|
|
Packit |
8f70b4 |
return 80;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *xgetcwd()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *cwd=getcwd(0,0); // glibc extension
|
|
Packit |
8f70b4 |
if(cwd) {
|
|
Packit |
8f70b4 |
xmalloc_register_block(cwd);
|
|
Packit |
8f70b4 |
return cwd;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int size=256;
|
|
Packit |
8f70b4 |
cwd=(char*)xmalloc(size);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(getcwd(cwd,size))
|
|
Packit |
8f70b4 |
return cwd;
|
|
Packit |
8f70b4 |
if(errno!=ERANGE)
|
|
Packit |
8f70b4 |
return strcpy(cwd,".");
|
|
Packit |
8f70b4 |
cwd=(char*)xrealloc(cwd,size*=2);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void xgetcwd_to(xstring& s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int size=256;
|
|
Packit |
8f70b4 |
for(;;) {
|
|
Packit |
8f70b4 |
s.get_space(size);
|
|
Packit |
8f70b4 |
if(getcwd(s.get_non_const(),size)) {
|
|
Packit |
8f70b4 |
s.set_length(strlen(s.get()));
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(errno!=ERANGE) {
|
|
Packit |
8f70b4 |
s.set(".");
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
size*=2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int parse_perms(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int p=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(strlen(s)!=9
|
|
Packit |
8f70b4 |
&& !(strlen(s)==10 && s[9]=='+')) // ACL tag
|
|
Packit |
8f70b4 |
bad: return -1;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(s[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('r'): p|=S_IRUSR; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[1])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('w'): p|=S_IWUSR; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[2])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('S'): p|=S_ISUID; break;
|
|
Packit |
8f70b4 |
case('s'): p|=S_ISUID; // fall-through
|
|
Packit |
8f70b4 |
case('x'): p|=S_IXUSR; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
s+=3;
|
|
Packit |
8f70b4 |
switch(s[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('r'): p|=S_IRGRP; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[1])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('w'): p|=S_IWGRP; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[2])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('S'): p|=S_ISGID; break;
|
|
Packit |
8f70b4 |
case('s'): p|=S_ISGID; // fall-through
|
|
Packit |
8f70b4 |
case('x'): p|=S_IXGRP; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
s+=3;
|
|
Packit |
8f70b4 |
switch(s[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('r'): p|=S_IROTH; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[1])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('w'): p|=S_IWOTH; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(s[2])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('T'): p|=S_ISVTX; break;
|
|
Packit |
8f70b4 |
case('t'): p|=S_ISVTX; // fall-through
|
|
Packit |
8f70b4 |
case('x'): p|=S_IXOTH; break;
|
|
Packit |
8f70b4 |
case('l'): case('L'): p|=S_ISGID; p&=~S_IXGRP; break;
|
|
Packit |
8f70b4 |
case('-'): break;
|
|
Packit |
8f70b4 |
default: goto bad;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return p;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// it does not prepend file type.
|
|
Packit |
8f70b4 |
const char *format_perms(int p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char s[10];
|
|
Packit |
8f70b4 |
memset(s,'-',9);
|
|
Packit |
8f70b4 |
if(p&0400) s[0]='r';
|
|
Packit |
8f70b4 |
if(p&0200) s[1]='w';
|
|
Packit |
8f70b4 |
if(p&0100) s[2]='x';
|
|
Packit |
8f70b4 |
if(p&0040) s[3]='r';
|
|
Packit |
8f70b4 |
if(p&0020) s[4]='w';
|
|
Packit |
8f70b4 |
if(p&0010) s[5]='x';
|
|
Packit |
8f70b4 |
if(p&0004) s[6]='r';
|
|
Packit |
8f70b4 |
if(p&0002) s[7]='w';
|
|
Packit |
8f70b4 |
if(p&0001) s[8]='x';
|
|
Packit |
8f70b4 |
if(p&01000) s[8]=(p&0001?'t':'T');
|
|
Packit |
8f70b4 |
if(p&02000) s[5]=(p&0010?'s':'S');
|
|
Packit |
8f70b4 |
if(p&04000) s[2]=(p&0100?'s':'S');
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char month_names[][4]={
|
|
Packit |
8f70b4 |
"Jan","Feb","Mar","Apr","May","Jun",
|
|
Packit |
8f70b4 |
"Jul","Aug","Sep","Oct","Nov","Dec",
|
|
Packit |
8f70b4 |
""
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
int parse_month(const char *m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=0; month_names[i][0]; i++)
|
|
Packit |
8f70b4 |
if(!strcasecmp(month_names[i],m))
|
|
Packit |
8f70b4 |
return(i%12);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int parse_year_or_time(const char *year_or_time,int *year,int *hour,int *minute)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(year_or_time[2]==':')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(2!=sscanf(year_or_time,"%2d:%2d",hour,minute))
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
*year=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(1!=sscanf(year_or_time,"%d",year))
|
|
Packit |
8f70b4 |
return -1;;
|
|
Packit |
8f70b4 |
*hour=*minute=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int guess_year(int month,int day,int hour,int minute)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const struct tm &now=SMTask::now;
|
|
Packit |
8f70b4 |
int year=now.tm_year+1900;
|
|
Packit |
8f70b4 |
if(month *32+ day
|
|
Packit |
8f70b4 |
> now.tm_mon*32+now.tm_mday+6)
|
|
Packit |
8f70b4 |
year--;
|
|
Packit |
8f70b4 |
return year;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int percent(off_t offset,off_t size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(offset>=size)
|
|
Packit |
8f70b4 |
return 100;
|
|
Packit |
8f70b4 |
// use floating point to avoid integer overflow.
|
|
Packit |
8f70b4 |
return int(double(offset)*100/size);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *squeeze_file_name(const char *name,int w)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static xstring buf;
|
|
Packit |
8f70b4 |
int mbflags=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
name=url::remove_password(name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int name_width=mbswidth(name,mbflags);
|
|
Packit |
8f70b4 |
if(name_width<=w)
|
|
Packit |
8f70b4 |
return name;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *b=basename_ptr(name);
|
|
Packit |
8f70b4 |
int b_width=name_width-mbsnwidth(name,b-name,mbflags);
|
|
Packit |
8f70b4 |
if(b_width<=w-4 && b_width>w-15)
|
|
Packit |
8f70b4 |
return buf.vset(".../",b,NULL);
|
|
Packit |
8f70b4 |
int b_len=strlen(b);
|
|
Packit |
8f70b4 |
while(b_width>(w<3?w-1:w-3) && b_len>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int ch_len=mblen(b,b_len);
|
|
Packit |
8f70b4 |
if(ch_len<1)
|
|
Packit |
8f70b4 |
ch_len=1;
|
|
Packit |
8f70b4 |
b_width-=mbsnwidth(b,ch_len,mbflags);
|
|
Packit |
8f70b4 |
b+=ch_len;
|
|
Packit |
8f70b4 |
b_len-=ch_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(w>=6)
|
|
Packit |
8f70b4 |
buf.set("...");
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
buf.set("<");
|
|
Packit |
8f70b4 |
return buf.append(b);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Converts struct tm to time_t, assuming the data in tm is UTC rather
|
|
Packit |
8f70b4 |
than local timezone (mktime assumes the latter).
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Contributed by Roger Beeman <beeman@cisco.com>, with the help of
|
|
Packit |
8f70b4 |
Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
|
|
Packit |
8f70b4 |
time_t
|
|
Packit |
8f70b4 |
mktime_from_utc (const struct tm *t)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct tm tc;
|
|
Packit |
8f70b4 |
memcpy(&tc, t, sizeof(struct tm));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* UTC times are never DST; if we say -1, we'll introduce odd localtime-
|
|
Packit |
8f70b4 |
* dependant errors. */
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
tc.tm_isdst = 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
time_t tl = mktime (&tc);
|
|
Packit |
8f70b4 |
if (tl == -1)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
time_t tb = mktime (gmtime (&tl));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void set_tz(const char *tz)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *put_tz;
|
|
Packit |
8f70b4 |
static int put_tz_alloc;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!tz)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsetenv("TZ");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xfree(put_tz);
|
|
Packit |
8f70b4 |
put_tz=0;
|
|
Packit |
8f70b4 |
put_tz_alloc=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
tzset();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int tz_len=strlen(tz)+4;
|
|
Packit |
8f70b4 |
char *new_tz=put_tz;
|
|
Packit |
8f70b4 |
if(tz_len>put_tz_alloc)
|
|
Packit |
8f70b4 |
new_tz=(char*)xmalloc(put_tz_alloc=tz_len);
|
|
Packit |
8f70b4 |
snprintf(new_tz,tz_len,"TZ=%s",tz);
|
|
Packit |
8f70b4 |
if(new_tz!=put_tz)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
putenv(new_tz);
|
|
Packit |
8f70b4 |
xfree(put_tz);
|
|
Packit |
8f70b4 |
put_tz=new_tz;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// now initialize libc variables from env TZ.
|
|
Packit |
8f70b4 |
tzset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static char *saved_tz=0;
|
|
Packit |
8f70b4 |
static void save_tz()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstrset(saved_tz,getenv("TZ"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static void restore_tz()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_tz(saved_tz);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
time_t mktime_from_tz(struct tm *t,const char *tz)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!tz || !*tz)
|
|
Packit |
8f70b4 |
return mktime(t);
|
|
Packit |
8f70b4 |
if(!strcasecmp(tz,"GMT"))
|
|
Packit |
8f70b4 |
return mktime_from_utc(t);
|
|
Packit |
8f70b4 |
if(isdigit((unsigned char)*tz) || *tz=='+' || *tz=='-')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int tz1_len=strlen(tz)+4;
|
|
Packit |
8f70b4 |
char *tz1=string_alloca(tz1_len);
|
|
Packit |
8f70b4 |
snprintf(tz1,tz1_len,"GMT%s",tz);
|
|
Packit |
8f70b4 |
tz=tz1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
save_tz();
|
|
Packit |
8f70b4 |
set_tz(tz);
|
|
Packit |
8f70b4 |
time_t res=mktime(t);
|
|
Packit |
8f70b4 |
restore_tz();
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool re_match(const char *line,const char *a,int flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!a || !*a)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
regex_t re;
|
|
Packit |
8f70b4 |
if(regcomp(&re,a,REG_EXTENDED|REG_NOSUB|flags))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
bool res=(0==regexec(&re,line,0,0,0));
|
|
Packit |
8f70b4 |
regfree(&re);
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& SubstTo(xstring& buf,const char *txt, const subst_t *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf.nset("",0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char str[3];
|
|
Packit |
8f70b4 |
bool last_subst_empty=true;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
while(*txt)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char ch = *txt++;
|
|
Packit |
8f70b4 |
const char *to_add = NULL;
|
|
Packit |
8f70b4 |
if(ch=='\\' && *txt && *txt!='\\')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ch=*txt++;
|
|
Packit |
8f70b4 |
if(ch >= '0' && ch < '8') {
|
|
Packit |
8f70b4 |
int len;
|
|
Packit |
8f70b4 |
unsigned code;
|
|
Packit |
8f70b4 |
txt--;
|
|
Packit |
8f70b4 |
if(sscanf(txt,"%3o%n",&code,&len)!=1)
|
|
Packit |
8f70b4 |
continue; // should never happen.
|
|
Packit |
8f70b4 |
ch=code;
|
|
Packit |
8f70b4 |
txt+=len;
|
|
Packit |
8f70b4 |
str[0]=ch;
|
|
Packit |
8f70b4 |
str[1]=0;
|
|
Packit |
8f70b4 |
to_add=str;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
if(ch=='?')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(last_subst_empty)
|
|
Packit |
8f70b4 |
txt++;
|
|
Packit |
8f70b4 |
to_add="";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
for(int i = 0; s[i].from; i++) {
|
|
Packit |
8f70b4 |
if(s[i].from != ch)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
to_add=s[i].to;
|
|
Packit |
8f70b4 |
if(!to_add)
|
|
Packit |
8f70b4 |
to_add = "";
|
|
Packit |
8f70b4 |
last_subst_empty = (*to_add==0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!to_add) {
|
|
Packit |
8f70b4 |
str[0]='\\';
|
|
Packit |
8f70b4 |
str[1]=ch;
|
|
Packit |
8f70b4 |
str[2]=0;
|
|
Packit |
8f70b4 |
to_add=str;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ch=='\\' && *txt=='\\')
|
|
Packit |
8f70b4 |
txt++;
|
|
Packit |
8f70b4 |
str[0]=ch;
|
|
Packit |
8f70b4 |
str[1]=0;
|
|
Packit |
8f70b4 |
to_add=str;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(to_add==0)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
buf.append(to_add);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return(buf);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void xgettimeofday(time_t *sec, int *usec)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef HAVE_GETTIMEOFDAY
|
|
Packit |
8f70b4 |
struct timeval tv;
|
|
Packit |
8f70b4 |
gettimeofday(&tv,0);
|
|
Packit |
8f70b4 |
if(sec) *sec = tv.tv_sec;
|
|
Packit |
8f70b4 |
if(usec) *usec = tv.tv_usec;
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
if(sec) time(sec);
|
|
Packit |
8f70b4 |
if(usec) *usec = 0;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *xstrftime(const char *format, const struct tm *tm)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *ret = NULL;
|
|
Packit |
8f70b4 |
int siz = 32;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
struct tm dummy;
|
|
Packit |
8f70b4 |
memset(&dummy, 0, sizeof(dummy));
|
|
Packit |
8f70b4 |
if(tm == NULL)
|
|
Packit |
8f70b4 |
tm = &dummy;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ret = (char *) xrealloc(ret, siz);
|
|
Packit |
8f70b4 |
int res=strftime(ret, siz, format, tm);
|
|
Packit |
8f70b4 |
if(res>0 && res
|
|
Packit |
8f70b4 |
return ret; /* success */
|
|
Packit |
8f70b4 |
/* more space */
|
|
Packit |
8f70b4 |
siz*=2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* /file/name -> /file
|
|
Packit |
8f70b4 |
* /file -> /
|
|
Packit |
8f70b4 |
* file/name -> "file"
|
|
Packit |
8f70b4 |
* file/name/ -> "file"
|
|
Packit |
8f70b4 |
* file -> ""
|
|
Packit |
8f70b4 |
* note: the last differs from dirname(1) (which would return ".")
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
void strip_trailing_slashes(xstring& ret)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=ret.length();
|
|
Packit |
8f70b4 |
while(len>0 && ret[len-1]=='/')
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
if(len==0 && ret[0]=='/')
|
|
Packit |
8f70b4 |
len=1+(ret[1]=='/');
|
|
Packit |
8f70b4 |
if(len>0)
|
|
Packit |
8f70b4 |
ret.truncate(len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& dirname_modify(xstring &ret)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
strip_trailing_slashes(ret);
|
|
Packit |
8f70b4 |
const char *slash=strrchr(ret,'/');
|
|
Packit |
8f70b4 |
if(!slash)
|
|
Packit |
8f70b4 |
ret.truncate(0); /* file with no path */
|
|
Packit |
8f70b4 |
else if(slash==ret)
|
|
Packit |
8f70b4 |
ret.truncate(1); /* the slash is the first character */
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
ret.truncate(slash-ret);
|
|
Packit |
8f70b4 |
return ret;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& dirname(const char *path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return dirname_modify(xstring::get_tmp(path));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char last_char(const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=strlen(str);
|
|
Packit |
8f70b4 |
return str[len-(len>0)];
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* How many bytes it will take to store LEN bytes in base64. */
|
|
Packit |
8f70b4 |
int
|
|
Packit |
8f70b4 |
base64_length(int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return (4 * (((len) + 2) / 3));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Encode the string S of length LENGTH to base64 format and place it
|
|
Packit |
8f70b4 |
to STORE. STORE will be 0-terminated, and must point to a writable
|
|
Packit |
8f70b4 |
buffer of at least 1+BASE64_LENGTH(length) bytes. */
|
|
Packit |
8f70b4 |
void
|
|
Packit |
8f70b4 |
base64_encode (const char *s, char *store, int length)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* Conversion table. */
|
|
Packit |
8f70b4 |
static const char tbl[64] = {
|
|
Packit |
8f70b4 |
'A','B','C','D','E','F','G','H',
|
|
Packit |
8f70b4 |
'I','J','K','L','M','N','O','P',
|
|
Packit |
8f70b4 |
'Q','R','S','T','U','V','W','X',
|
|
Packit |
8f70b4 |
'Y','Z','a','b','c','d','e','f',
|
|
Packit |
8f70b4 |
'g','h','i','j','k','l','m','n',
|
|
Packit |
8f70b4 |
'o','p','q','r','s','t','u','v',
|
|
Packit |
8f70b4 |
'w','x','y','z','0','1','2','3',
|
|
Packit |
8f70b4 |
'4','5','6','7','8','9','+','/'
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
int i;
|
|
Packit |
8f70b4 |
unsigned char *p = (unsigned char *)store;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Transform the 3x8 bits to 4x6 bits, as required by base64. */
|
|
Packit |
8f70b4 |
for (i = 0; i < length; i += 3)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*p++ = tbl[s[0] >> 2];
|
|
Packit |
8f70b4 |
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
|
|
Packit |
8f70b4 |
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
|
|
Packit |
8f70b4 |
*p++ = tbl[s[2] & 0x3f];
|
|
Packit |
8f70b4 |
s += 3;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
/* Pad the result if necessary... */
|
|
Packit |
8f70b4 |
if (i == length + 1)
|
|
Packit |
8f70b4 |
*(p - 1) = '=';
|
|
Packit |
8f70b4 |
else if (i == length + 2)
|
|
Packit |
8f70b4 |
*(p - 1) = *(p - 2) = '=';
|
|
Packit |
8f70b4 |
/* ...and zero-terminate it. */
|
|
Packit |
8f70b4 |
*p = '\0';
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool temporary_network_error(int err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(EPIPE):
|
|
Packit |
8f70b4 |
case(EIO):
|
|
Packit |
8f70b4 |
case(ETIMEDOUT):
|
|
Packit |
8f70b4 |
#ifdef ECONNRESET
|
|
Packit |
8f70b4 |
case(ECONNRESET):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
case(ECONNREFUSED):
|
|
Packit |
8f70b4 |
#ifdef EHOSTUNREACH
|
|
Packit |
8f70b4 |
case(EHOSTUNREACH):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef EHOSTDOWN
|
|
Packit |
8f70b4 |
case(EHOSTDOWN):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef ENETRESET
|
|
Packit |
8f70b4 |
case(ENETRESET):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef ENETUNREACH
|
|
Packit |
8f70b4 |
case(ENETUNREACH):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef ENETDOWN
|
|
Packit |
8f70b4 |
case(ENETDOWN):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef ECONNABORTED
|
|
Packit |
8f70b4 |
case(ECONNABORTED):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef EADDRNOTAVAIL
|
|
Packit |
8f70b4 |
case(EADDRNOTAVAIL):
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *get_home()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *home=NULL;
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
return home;
|
|
Packit |
8f70b4 |
home=getenv("HOME");
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
return home;
|
|
Packit |
8f70b4 |
struct passwd *pw=getpwuid(getuid());
|
|
Packit |
8f70b4 |
if(pw && pw->pw_dir)
|
|
Packit |
8f70b4 |
return home=pw->pw_dir;
|
|
Packit |
8f70b4 |
return NULL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *get_lftp_home_nocreate()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *lftp_home=NULL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(lftp_home)
|
|
Packit |
8f70b4 |
return *lftp_home?lftp_home:NULL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
lftp_home=getenv("LFTP_HOME");
|
|
Packit |
8f70b4 |
if(!lftp_home)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *h=get_home();
|
|
Packit |
8f70b4 |
if(h)
|
|
Packit |
8f70b4 |
lftp_home=xstring::cat(h,"/.lftp",NULL).borrow();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
return NULL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
lftp_home=xstrdup(lftp_home);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return *lftp_home?lftp_home:NULL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *get_lftp_home_if_exists()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *home=get_lftp_home_nocreate();
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(home,&st)==-1 || !S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
return NULL;
|
|
Packit |
8f70b4 |
return home;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// new XDG directories
|
|
Packit |
8f70b4 |
const char *get_lftp_dir(char *&cached_dir,const char *env,const char *def)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(cached_dir)
|
|
Packit |
8f70b4 |
return cached_dir;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// use old existing directory for compatibility
|
|
Packit |
8f70b4 |
const char *dir=get_lftp_home_if_exists();
|
|
Packit |
8f70b4 |
if(dir)
|
|
Packit |
8f70b4 |
return cached_dir=xstrdup(dir);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// use explicit directory if specified, otherwise use default under home
|
|
Packit |
8f70b4 |
const char *home=getenv(env);
|
|
Packit |
8f70b4 |
if(home) {
|
|
Packit |
8f70b4 |
// explicit XDG dir
|
|
Packit |
8f70b4 |
(void)mkdir(home,0755);
|
|
Packit |
8f70b4 |
dir=xstring::cat(home,"/lftp",NULL);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
home=get_home();
|
|
Packit |
8f70b4 |
if(!home)
|
|
Packit |
8f70b4 |
return NULL;
|
|
Packit |
8f70b4 |
xstring& path=xstring::get_tmp(home);
|
|
Packit |
8f70b4 |
path.append('/');
|
|
Packit |
8f70b4 |
const char *slash=strchr(def,'/');
|
|
Packit |
8f70b4 |
if(slash) {
|
|
Packit |
8f70b4 |
path.append(def,slash-def);
|
|
Packit |
8f70b4 |
(void)mkdir(path,0755);
|
|
Packit |
8f70b4 |
path.append(slash);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
path.append(def);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
(void)mkdir(path,0755);
|
|
Packit |
8f70b4 |
dir=path.append("/lftp");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
(void)mkdir(dir,0755);
|
|
Packit |
8f70b4 |
return cached_dir=xstrdup(dir);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *get_lftp_config_dir()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *config_dir;
|
|
Packit |
8f70b4 |
return get_lftp_dir(config_dir,"XDG_CONFIG_HOME",".config");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *get_lftp_data_dir()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *data_dir;
|
|
Packit |
8f70b4 |
return get_lftp_dir(data_dir,"XDG_DATA_HOME",".local/share");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *get_lftp_cache_dir()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static char *cache_dir;
|
|
Packit |
8f70b4 |
return get_lftp_dir(cache_dir,"XDG_CACHE_HOME",".cache");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *memrchr(const char *buf,char c,size_t len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf+=len;
|
|
Packit |
8f70b4 |
while(len-->0)
|
|
Packit |
8f70b4 |
if(*--buf==c)
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool is_shell_special(char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch (c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case '\'':
|
|
Packit |
8f70b4 |
case '(': case ')':
|
|
Packit |
8f70b4 |
case '!': case '{': case '}': /* reserved words */
|
|
Packit |
8f70b4 |
case '^':
|
|
Packit |
8f70b4 |
case '$': case '`': /* expansion chars */
|
|
Packit |
8f70b4 |
case '*': case '[': case '?': case ']': /* globbing chars */
|
|
Packit |
8f70b4 |
case ' ': case '\t': case '\n': /* IFS white space */
|
|
Packit |
8f70b4 |
case '"': case '\\': /* quoting chars */
|
|
Packit |
8f70b4 |
case '|': case '&': case ';': /* shell metacharacters */
|
|
Packit |
8f70b4 |
case '<': case '>':
|
|
Packit |
8f70b4 |
case '#': /* comment char */
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring& shell_encode(const char *string,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!string)
|
|
Packit |
8f70b4 |
return xstring::null;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static xstring result;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
result.get_space(2 + 2 * len);
|
|
Packit |
8f70b4 |
char *r = result.get_non_const();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(string[0]=='-' || string[0]=='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*r++='.';
|
|
Packit |
8f70b4 |
*r++='/';
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int c;
|
|
Packit |
8f70b4 |
for (const char *s = string; s && (c = *s); s++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if (is_shell_special(c))
|
|
Packit |
8f70b4 |
*r++ = '\\';
|
|
Packit |
8f70b4 |
*r++ = c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
result.set_length(r-result);
|
|
Packit |
8f70b4 |
return (result);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void remove_tags(char *buf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=strlen(buf);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *less=strchr(buf,'<');
|
|
Packit |
8f70b4 |
char *amp=strstr(buf," ");
|
|
Packit |
8f70b4 |
if(!less && !amp)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(amp && (!less || amp
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
amp[0]=' ';
|
|
Packit |
8f70b4 |
memmove(amp+1,amp+6,len-(amp+6-buf)+1);
|
|
Packit |
8f70b4 |
len-=amp+6-buf;
|
|
Packit |
8f70b4 |
buf=amp+1;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
char *more=strchr(less+1,'>');
|
|
Packit |
8f70b4 |
if(!more)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
memmove(less,more+1,len-(more+1-buf)+1);
|
|
Packit |
8f70b4 |
len-=more+1-buf;
|
|
Packit |
8f70b4 |
buf=less;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void rtrim(char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=strlen(s);
|
|
Packit |
8f70b4 |
while(len>0 && (s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\r'))
|
|
Packit |
8f70b4 |
s[--len]=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool in_foreground_pgrp()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static int tty_fd;
|
|
Packit |
8f70b4 |
if(tty_fd==-1)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
pid_t pg=tcgetpgrp(tty_fd);
|
|
Packit |
8f70b4 |
if(pg==(pid_t)-1 && !isatty(tty_fd)) {
|
|
Packit |
8f70b4 |
tty_fd=open("/dev/tty",O_RDONLY);
|
|
Packit |
8f70b4 |
if(tty_fd==-1)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
pg=tcgetpgrp(tty_fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pg==(pid_t)-1 || pg==getpgrp())
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void random_init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static bool init;
|
|
Packit |
8f70b4 |
if(!init)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
srandom(time(NULL)+getpid());
|
|
Packit |
8f70b4 |
init=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
double random01()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return random()/2147483648.0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <sys/utsname.h>
|
|
Packit |
8f70b4 |
const char *get_nodename()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static struct utsname u;
|
|
Packit |
8f70b4 |
if(uname(&u)==0)
|
|
Packit |
8f70b4 |
return u.nodename;
|
|
Packit |
8f70b4 |
return "NODE";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *xhuman(long long n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *buf=xstring::tmp_buf(LONGEST_HUMAN_READABLE + 1);
|
|
Packit |
8f70b4 |
return human_readable(n, buf, human_autoscale|human_SI, 1, 1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *xidna_to_ascii(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if LIBIDN2
|
|
Packit |
8f70b4 |
if(!name)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
static xstring_c name_ace_tmp;
|
|
Packit |
8f70b4 |
name_ace_tmp.unset();
|
|
Packit |
8f70b4 |
if(idn2_to_ascii_lz(name,name_ace_tmp.buf_ptr(),0)==IDN2_OK) {
|
|
Packit |
8f70b4 |
xmalloc_register_block((void*)name_ace_tmp.get());
|
|
Packit |
8f70b4 |
return name_ace_tmp;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif//LIBIDN2
|
|
Packit |
8f70b4 |
return name;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool xtld_name_ok(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if LIBIDN2
|
|
Packit |
8f70b4 |
if(mbswidth(name,MBSW_REJECT_INVALID|MBSW_REJECT_UNPRINTABLE)<=0)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(idn2_lookup_ul(name,NULL,0)==IDN2_OK)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
#endif//LIBIDN2
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool is_ipv4_address(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct in_addr addr;
|
|
Packit |
8f70b4 |
return inet_pton(AF_INET,s,&addr)>0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool is_ipv6_address(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
struct in6_addr addr;
|
|
Packit |
8f70b4 |
return inet_pton(AF_INET6,s,&addr)>0;
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int lftp_fallocate(int fd,off_t sz)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if defined(HAVE_FALLOCATE)
|
|
Packit |
8f70b4 |
return fallocate(fd,0,0,sz);
|
|
Packit |
8f70b4 |
#elif defined(HAVE_POSIX_FALLOCATE)
|
|
Packit |
8f70b4 |
return posix_fallocate(fd,0,sz);
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
errno=ENOSYS;
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void call_dynamic_hook(const char *name) {
|
|
Packit |
8f70b4 |
#if defined(HAVE_DLOPEN) && defined(RTLD_DEFAULT)
|
|
Packit |
8f70b4 |
typedef void (*func)();
|
|
Packit |
8f70b4 |
func f=(func)dlsym(RTLD_DEFAULT,name);
|
|
Packit |
8f70b4 |
if(f) f();
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|