#ifdef RCS
static char rcsid[]=
"$Id: exopen.c,v 1.44 2001/08/26 21:10:11 guenther Exp $";
#endif
#include "procmail.h"
#include "acommon.h"
#include "robust.h"
#include "misc.h"
#include "exopen.h"
#include "lastdirsep.h"
#include "sublib.h"
static const char*safehost P((void))
{ static const char*sname=0;
if(!sname)
{ char*to;const char*from=hostname();
int badchars=0;
for(to=(char*)from;*to;to++)
if(*to=='/'||*to==':'||*to=='\\')
badchars++;
if(!badchars)
sname=from;
else if(!(sname=to=malloc(3*badchars+strlen(from)+1)))
sname="";
else
{ int c;
while(badchars)
switch(c=(unsigned char)*from++)
{ default:*to++=c;
break;
case '\0':from--;to--;
break;
case '/':case ':':case '\\':
*to++='\\';
*to++='0'+(c>>6);
*to++='0'+((c>>3)&7);
*to++='0'+(c&7);
badchars--;
}
strcpy(to,from);
}
}
return sname;
}
int unique(full,p,len,mode,verbos,flags)char*const full;char*p;
const size_t len;const mode_t mode;const int verbos,flags;
{ static const char s2c[]=".,+%";static int serial=STRLEN(s2c);
static time_t t;char*dot,*end,*host;struct stat filebuf;
int nicediff,i,didnice,retry=RETRYunique;
if(flags&doCHOWN)
{ nicediff=nice(0);SETerrno(0);nicediff-=nice(-NICE_RANGE);
didnice=!errno;
}
end=full+len;
if(end-p<=UNIQnamelen-1)
goto ret0;
if(flags&doMAILDIR)
dot=p;
else
*p=UNIQ_PREFIX,dot=ultoan((unsigned long)thepid,p+1);
if(serial<STRLEN(s2c))
goto in;
do
{ if(serial>STRLEN(s2c)-1)
{ ;{ time_t t2;
while(t==(t2=time((time_t*)0)))
ssleep(1);
serial=0;t=t2;
}
in: if(flags&doMAILDIR)
{ dot=ultstr(0,(unsigned long)t,p);
*dot='.';
dot=ultstr(0,(unsigned long)thepid,dot+1);
*dot++='_';
host=dot+2;
}
else
host=1+ultoan((unsigned long)t,dot+1);
host[-1]='.';
strlcpy(host,safehost(),end-host);
}
*dot=(flags&doMAILDIR)?'0'+serial:s2c[serial];
serial++;
i=lstat(full,&filebuf);
#ifdef ENAMETOOLONG
if(i&&errno==ENAMETOOLONG)
{ char*op,*ldp;
op=lastdirsep(full);
ldp=op+1;
if(end-op>MINnamelen+1)
op+=MINnamelen+1;
else
op=end-1;
do
*--op='\0';
while((i=lstat(full,&filebuf))&&errno==ENAMETOOLONG&&op>ldp);
}
#endif
}
#ifndef O_CREAT
#define ropen(path,type,mode) creat(path,mode)
#endif
while((!i||errno!=ENOENT||
(0>(i=ropen(full,O_WRONLY|O_CREAT|O_EXCL,mode))&&errno==EEXIST))&&
(i= -1,retry--));
if(flags&doCHOWN&&didnice)
nice(nicediff);
if(i<0)
{ if(verbos)
writeerr(full);
goto ret0;
}
#ifdef NOfstat
if(flags&doCHOWN)
{ if(
#else
if(flags&doCHECK)
{ struct stat fdbuf;
fstat(i,&fdbuf);
#define NEQ(what) (fdbuf.what!=filebuf.what)
if(lstat(full,&filebuf)||filebuf.st_nlink!=1||filebuf.st_size||
NEQ(st_dev)||NEQ(st_ino)||NEQ(st_uid)||NEQ(st_gid)||
flags&doCHOWN&&
#endif
chown(full,uid,sgid))
{ rclose(i);unlink(full);
ret0: return flags&doFD?-1:0;
}
}
if(flags&doLOCK)
rwrite(i,"0",1);
if(flags&doFD)
return i;
rclose(i);
return 1;
}
int myrename(old,newn)const char*const old,*const newn;
{ int fd,serrno;
fd=hlink(old,newn);serrno=errno;unlink(old);
if(fd>0)rclose(fd-1);
SETerrno(serrno);
return fd<0?-1:0;
}
int rlink(old,newn,st)const char*const old,*const newn;struct stat*st;
{ if(link(old,newn))
{ register int serrno,ret;struct stat sto,stn;
serrno=errno;ret= -1;
#undef NEQ
#define NEQ(what) (sto.what!=stn.what)
if(lstat(old,&sto)||(ret=1,lstat(newn,&stn)||
NEQ(st_dev)||NEQ(st_ino)||NEQ(st_uid)||NEQ(st_gid)||
S_ISLNK(sto.st_mode)))
{ SETerrno(serrno);
if(st&&ret>0)
{ *st=sto;
return ret;
}
return -1;
}
}
return 0;
}
int hlink(old,newn)const char*const old,*const newn;
{ int ret;struct stat stbuf;
if(0<(ret=rlink(old,newn,&stbuf)))
{ int fd;
#ifdef O_CREAT
if(stbuf.st_nlink<2&&errno==EXDEV&&
0<=(fd=ropen(newn,O_WRONLY|O_CREAT|O_EXCL,stbuf.st_mode)))
return fd+1;
#endif
return -1;
}
return ret;
}