#include <stdio.h>
#ifndef TRACE
#undef NULL
#endif
#include "ex.h"
#include "ex_temp.h"
#include "ex_tty.h"
#include "ex_tune.h"
#include <pwd.h>
#include <locale.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#define DIRSIZ MAXNAMLEN
short tfile = -1;
unsigned char mydir[PATH_MAX+1];
#define NENTRY 50
unsigned char nb[BUFSIZE];
int vercnt;
void rputfile(void);
void rsyserror(void);
void searchdir(unsigned char *);
void scrapbad(void);
void findtmp(unsigned char *);
void listfiles(unsigned char *);
int
main(int argc, char *argv[])
{
unsigned char string[50];
unsigned char *cp;
int c, b, i;
int rflg = 0, errflg = 0;
int label;
line *tmpadr;
extern unsigned char *mypass();
struct passwd *pp = getpwuid(getuid());
unsigned char rmcmd[PATH_MAX+1];
(void)setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void)textdomain(TEXT_DOMAIN);
cp = string;
strcpy(mydir, USRPRESERVE);
if (pp == NULL) {
fprintf(stderr, gettext("Unable to get user's id\n"));
exit(-1);
}
strcat(mydir, pp->pw_name);
fendcore = (line *) sbrk(0);
dot = zero = dol = fendcore;
one = zero + 1;
endcore = fendcore - 2;
iblock = oblock = -1;
while ((c=getopt(argc, (char **)argv, "rx")) != EOF)
switch (c) {
case 'r':
rflg++;
break;
case 'x':
xflag++;
break;
case '?':
errflg++;
break;
}
argc -= optind;
argv = &argv[optind];
if (errflg)
exit(2);
if (rflg && argc == 0) {
fprintf(stderr,"%s:\n", mydir);
listfiles(mydir);
fprintf(stderr,"%s:\n", TMPDIR);
listfiles((unsigned char *)TMPDIR);
exit(0);
}
if (argc != 2)
error(gettext(" Wrong number of arguments to exrecover"), 0);
CP(file, argv[1]);
findtmp((unsigned char *)argv[0]);
(void)cftime((char *)cp, "%a %h %d %T", &H.Time);
fprintf(stderr, vercnt > 1 ?
gettext(" [Dated: %s, newest of %d saved]") :
gettext(" [Dated: %s]"), cp, vercnt);
fprintf(stderr, "\r\n");
if(H.encrypted) {
if(xflag) {
kflag = run_setkey(perm, (unsigned char *)getenv("CrYpTkEy"));
} else
kflag = run_setkey(perm, mypass("Enter key:"));
if(kflag == -1) {
kflag = 0;
xflag = 0;
fprintf(stderr,gettext("Encryption facility not available\n"));
exit(-1);
}
xtflag = 1;
if (makekey(tperm) != 0) {
xtflag = 0;
fprintf(stderr,gettext("Warning--Cannot encrypt temporary buffer\n"));
exit(-1);
}
}
fprintf(stderr,gettext("\r\n [Hit return to continue]"));
fflush(stderr);
setbuf(stdin, (char *)NULL);
while((c = getchar()) != '\n' && c != '\r');
H.Flines++;
if ((int) sbrk((int) (H.Flines * sizeof (line))) == -1)
error(gettext(" Not enough core for lines"), 0);
#ifdef DEBUG
fprintf(stderr, "%d lines\n", H.Flines);
#endif
b = 0;
while (H.Flines > 0) {
(void)lseek(tfile, (long) blocks[b] * BUFSIZE, 0);
i = H.Flines < BUFSIZE / sizeof (line) ?
H.Flines * sizeof (line) : BUFSIZE;
if (read(tfile, (char *) dot, i) != i) {
perror((char *)nb);
exit(1);
}
dot += i / sizeof (line);
H.Flines -= i / sizeof (line);
b++;
}
dot--; dol = dot;
scrapbad();
if (dol > zero) {
addr1 = one; addr2 = dol; io = 1;
rputfile();
}
if (nb[0] == '/') {
(void)unlink((const char *)nb);
sprintf((char *)rmcmd, "rmdir %s 2> /dev/null", (char *)mydir);
system((char *)rmcmd);
}
return (0);
}
void
error(str, inf)
unsigned char *str;
int inf;
{
struct termio termio;
if (inf)
fprintf(stderr, (char *)str, inf);
else
fprintf(stderr, (char *)str);
ioctl(2, TCGETA, &termio);
if (termio.c_lflag & ICANON)
fprintf(stderr, "\n");
exit(1);
}
struct svfile {
unsigned char sf_name[FNSIZE + 1];
int sf_lines;
unsigned char sf_entry[DIRSIZ + 1];
time_t sf_time;
short sf_encrypted;
};
void enter(struct svfile *, unsigned char *, int);
void
listfiles(unsigned char *dirname)
{
DIR *dir;
struct dirent64 *direntry;
int ecount, qucmp();
int f;
unsigned char cp[50];
unsigned char cp2[50];
unsigned char *filname;
struct svfile *fp, svbuf[NENTRY];
if ((dir = opendir((char *)dirname)) == NULL)
{
fprintf(stderr,gettext("No files saved.\n"));
return;
}
if (chdir((const char *)dirname) < 0) {
perror((char *)dirname);
return;
}
fp = &svbuf[0];
ecount = 0;
while ((direntry = readdir64(dir)) != NULL)
{
filname = (unsigned char *)direntry->d_name;
if (filname[0] != 'E')
continue;
#ifdef DEBUG
fprintf(stderr, "considering %s\n", filname);
#endif
f = open(filname, 0);
if (f < 0) {
#ifdef DEBUG
fprintf(stderr, "open failed\n");
#endif
continue;
}
if (read(f, (char *) &H, sizeof H) != sizeof H) {
#ifdef DEBUG
fprintf(stderr, "could not read header\n");
#endif
(void)close(f);
continue;
}
(void)close(f);
if (getuid() != H.Uid) {
#ifdef DEBUG
fprintf(stderr, "uid wrong\n");
#endif
continue;
}
enter(fp++, filname, ecount);
ecount++;
#ifdef DEBUG
fprintf(stderr, "entered file %s\n", filname);
#endif
}
(void)closedir(dir);
if (ecount == 0) {
fprintf(stderr, gettext("No files saved.\n"));
return;
}
qsort(&svbuf[0], ecount, sizeof svbuf[0], qucmp);
for (fp = &svbuf[0]; fp < &svbuf[ecount]; fp++) {
(void)cftime((char *)cp, "%a %b %d", &fp->sf_time);
(void)cftime((char *)cp2, "%R", &fp->sf_time);
fprintf(stderr,
gettext("On %s at %s, saved %d lines of file \"%s\" "),
cp, cp2, fp->sf_lines, fp->sf_name);
fprintf(stderr, "%s\n",
(fp->sf_encrypted) ? gettext("[ENCRYPTED]") : "");
}
}
void
enter(struct svfile *fp, unsigned char *fname, int count)
{
unsigned char *cp, *cp2;
struct svfile *f, *fl;
time_t curtime;
f = 0;
if (count >= NENTRY) {
fl = fp - count + NENTRY - 1;
curtime = fl->sf_time;
for (f = fl; --f > fp-count; )
if (f->sf_time < curtime)
curtime = f->sf_time;
for (f = fl; --f > fp-count; )
if (f->sf_time == curtime)
break;
fp = f;
}
fp->sf_time = H.Time;
fp->sf_lines = H.Flines;
fp->sf_encrypted = H.encrypted;
for (cp2 = fp->sf_name, cp = savedfile; *cp;)
*cp2++ = *cp++;
*cp2++ = 0;
for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;)
*cp2++ = *cp++;
*cp2++ = 0;
}
int
qucmp(struct svfile *p1, struct svfile *p2)
{
int t;
if (t = strcmp(p1->sf_name, p2->sf_name))
return(t);
if (p1->sf_time > p2->sf_time)
return(-1);
return(p1->sf_time < p2->sf_time);
}
unsigned char bestnb[BUFSIZE];
long besttime = 0;
int bestfd;
void
findtmp(unsigned char *dir)
{
bestnb[0] = 0;
bestfd = -1;
searchdir(dir);
if (chdir((const char *)mydir) == 0)
searchdir(mydir);
if (bestfd != -1) {
tfile = bestfd;
CP(nb, bestnb);
(void)lseek(tfile, 0l, 0);
if (read(tfile, (char *) &H, sizeof H) == sizeof H)
return;
}
error((unsigned char *)gettext(" File not found"), 0);
}
void
searchdir(unsigned char *dirname)
{
struct dirent64 *direntry;
DIR *dir;
unsigned char dbuf[BUFSIZE];
unsigned char *filname;
if ((dir = opendir((char *)dirname)) == NULL)
return;
while ((direntry = readdir64(dir)) != NULL)
{
filname = (unsigned char *)direntry->d_name;
if (filname[0] != 'E' || filname[1] != 'x')
continue;
(void)strcat(strcat(strcpy(nb, dirname), "/"), filname);
if (yeah(nb)) {
if (H.Time > besttime) {
(void)close(bestfd);
bestfd = dup(tfile);
besttime = H.Time;
CP(bestnb, nb);
}
vercnt++;
}
(void)close(tfile);
}
(void)closedir(dir);
}
int
yeah(unsigned char *name)
{
tfile = open(name, 2);
if (tfile < 0)
return (0);
if (read(tfile, (char *) &H, sizeof H) != sizeof H) {
nope:
(void)close(tfile);
return (0);
}
if (!eq(savedfile, file))
goto nope;
if (getuid() != H.Uid)
goto nope;
(void)lseek(tfile, (long)(BUFSIZE*HBLKS-8), 0);
(void)write(tfile, "LOST", 5);
return (1);
}
void
scrapbad(void)
{
line *ip;
struct stat64 stbuf;
off_t size, maxt;
int bno, cnt, bad, was;
unsigned char bk[BUFSIZE];
(void)fstat64(tfile, &stbuf);
size = (off_t)stbuf.st_size;
maxt = (size >> SHFT) | (BNDRY-1);
bno = (maxt >> OFFBTS) & BLKMSK;
#ifdef DEBUG
fprintf(stderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno);
#endif
while (bno > 0) {
(void)lseek(tfile, (long) BUFSIZE * bno, 0);
cnt = read(tfile, (char *) bk, BUFSIZE);
if(xtflag)
if (run_crypt(0L, bk, CRSIZE, tperm) == -1)
rsyserror();
#ifdef DEBUG
fprintf(stderr,"UNENCRYPTED: BLK %d\n",bno);
#endif
while (cnt > 0)
if (bk[--cnt] == 0)
goto null;
bno--;
}
null:
maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1;
#ifdef DEBUG
fprintf(stderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt);
#endif
was = bad = 0;
for (ip = one; ip <= dol; ip++)
if (*ip > maxt) {
#ifdef DEBUG
fprintf(stderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt);
#endif
if (was == 0)
was = ip - zero;
*ip = ((HBLKS*BUFSIZE)-8) >> SHFT;
} else if (was) {
if (bad == 0)
fprintf(stderr, gettext(" [Lost line(s):"));
fprintf(stderr, " %d", was);
if ((ip - 1) - zero > was)
fprintf(stderr, "-%d", (ip - 1) - zero);
bad++;
was = 0;
}
if (was != 0) {
if (bad == 0)
fprintf(stderr, " [Lost line(s):");
fprintf(stderr, " %d", was);
if (dol - zero != was)
fprintf(stderr, "-%d", dol - zero);
bad++;
}
if (bad)
fprintf(stderr, "]");
}
int cntch, cntln, cntodd, cntnull;
void
rputfile(void)
{
line *a1;
unsigned char *fp, *lp;
int nib;
a1 = addr1;
clrstats();
cntln = addr2 - a1 + 1;
if (cntln == 0)
return;
nib = BUFSIZE;
fp = genbuf;
do {
#ifdef DEBUG
fprintf(stderr,"GETTING A LINE \n");
#endif
getaline(*a1++);
lp = linebuf;
#ifdef DEBUG
fprintf(stderr,"LINE:%s\n",linebuf);
#endif
for (;;) {
if (--nib < 0) {
nib = fp - genbuf;
if (write(io, genbuf, nib) != nib)
wrerror();
cntch += nib;
nib = BUFSIZE;
fp = genbuf;
}
if ((*fp++ = *lp++) == 0) {
fp[-1] = '\n';
break;
}
}
} while (a1 <= addr2);
nib = fp - genbuf;
if (write(io, genbuf, nib) != nib)
wrerror();
cntch += nib;
}
void
wrerror(void)
{
rsyserror();
}
void
clrstats(void)
{
ninbuf = 0;
cntch = 0;
cntln = 0;
cntnull = 0;
cntodd = 0;
}
#define READ 0
#define WRITE 1
void
getaline(line tl)
{
unsigned char *bp, *lp;
int nl;
lp = linebuf;
bp = getblock(tl);
nl = nleft;
tl &= ~OFFMSK;
while (*lp++ = *bp++)
if (--nl == 0) {
bp = getblock(tl += INCRMT);
nl = nleft;
}
}
int read();
int write();
unsigned char *
getblock(atl)
line atl;
{
int bno, off;
unsigned char *p1, *p2;
int n;
bno = (atl >> OFFBTS) & BLKMSK;
#ifdef DEBUG
fprintf(stderr,"GETBLOCK: BLK %d\n",bno);
#endif
off = (atl << SHFT) & LBTMSK;
if (bno >= NMBLKS)
error((unsigned char *)gettext(" Tmp file too large"));
nleft = BUFSIZE - off;
if (bno == iblock)
return (ibuff + off);
iblock = bno;
blkio(bno, ibuff, read);
if(xtflag)
if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1)
rsyserror();
#ifdef DEBUG
fprintf(stderr,"UNENCRYPTED: BLK %d\n",bno);
#endif
return (ibuff + off);
}
void
blkio(short b, unsigned char *buf, int (*iofcn)())
{
int rc;
lseek(tfile, (long) (unsigned) b * BUFSIZE, 0);
if ((rc =(*iofcn)(tfile, buf, BUFSIZE)) != BUFSIZE) {
(void)fprintf(stderr,gettext("Failed on BLK: %d with %d/%d\n"),b,rc,BUFSIZE);
perror("");
rsyserror();
}
}
void
rsyserror(void)
{
int save_err = errno;
dirtcnt = 0;
write(2, " ", 1);
error(strerror(save_err));
exit(1);
}
static int intrupt;
static void catch();
unsigned char *
mypass(prompt)
unsigned char *prompt;
{
struct termio ttyb;
unsigned short flags;
unsigned char *p;
int c;
static unsigned char pbuf[9];
void (*sig)();
setbuf(stdin, (char*)NULL);
sig = signal(SIGINT, catch);
intrupt = 0;
(void) ioctl(fileno(stdin), TCGETA, &ttyb);
flags = ttyb.c_lflag;
ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
(void) ioctl(fileno(stdin), TCSETAF, &ttyb);
(void) fputs((char *)prompt, stderr);
for(p=pbuf; !intrupt && (c = getc(stdin)) != '\n' && c!= '\r' && c != EOF; ) {
if(p < &pbuf[8])
*p++ = c;
}
*p = '\0';
(void) putc('\n', stderr);
ttyb.c_lflag = flags;
(void) ioctl(fileno(stdin), TCSETA, &ttyb);
(void) signal(SIGINT, sig);
if(intrupt)
(void) kill(getpid(), SIGINT);
return(pbuf);
}
static void
catch()
{
++intrupt;
}