#

/*
 * restore from incremental dumps
 */

char	*dargv[]
{
	0,
	"t",
	0
};
char	*ifile	"/dev/rmt0";
char	*ifile1	"/dev/rmt2";
char	*ofile;
#include "../head/ino.h"
#include "../head/filsys.h"

struct	filsys	sblock;
int	isize;
int	*talist;
int	bufsiz;
int	fi;
int	*bigbuf;
int	buf[256];
int	dbuf[256];
int	cbuf[256];
char	*date[2];
char	*ddate[2];
int	fo;
int	pher;
char	*tsize;
int	recsiz;
int	iflg;
int	wflg;
int	cflg;
char	file[10];
int	ilist[100];

main(argc, argv)
char **argv;
{
	char *key;
	register *tap, *p;
	register struct inode *ip;
	int i, com, sz, *q, l;

	if(argc == 1) {
		argv = dargv;
		for(argc = 1; dargv[argc]; argc++);
	}

	argc--;
	argv++;
	key = *argv;
	while(*key)
	switch(*key++) {
	default:
		printf("bad character in key\n");
		exit(0);

	case 't':
	case 'r':
	case 'x':
		com = key[-1];
		continue;

	case 'i':
		iflg++;
		continue;

	case '-':
		continue;

	case 'c':
		cflg++;
		continue;

	case 'f':
		argv++;
		argc--;
		ifile = *argv;
		continue;

	case 'w':
		wflg++;
		continue;

	case 'q':
		ifile = ifile1;
		continue;

	}
	otape(1);
	i = read(fi,buf,512);
	if(i != 512){
		printf("Read error in super-block !  Is tape drive key set ?\n");
	}
	i = 0;
	tap = buf;
	for(l = 0;l < 256;l++)
		i =+ *tap++;
	if(i != 031415){
		printf("Checksum error in the super-block !\n");
		if(!iflg)
			exit(0);
	}
	close(fi);
	otape(0);
	tap = buf;
	isize = *tap++;
	*tap++;		/* fsize */
	date[0] = *tap++;
	date[1] = *tap++;
	ddate[0] = *tap++;
	ddate[1] = *tap++;
	tsize = *tap++;
	recsiz = *tap++;
	if(recsiz == 0)
		recsiz = 1;
	printf("The record size of this tape = %d blocks\n",recsiz);
	bufsiz = recsiz*512;
	bigbuf = sbrk(bufsiz);
	if(bigbuf == -1){
		printf("No memory !\n");
		exit(0);
	}
	rawin(1,0,1);
	sread(buf, 0);
	i = size(0, isize*32);
	talist = sbrk(i*512);
	if(talist == -1){
		printf("NO memory !\n");
		exit(0);
	}
	tap = talist;
	while(i--) {
		tread(tap, 0);
		tap =+ 256;
	}
	switch(com) {

case 't':
	l = 0;
	com = 0;
	pdate(ddate);
	pdate(date);
	tap = talist;
	for(i=0; i<isize*16; i++) {
		sz = *tap++;
		if(sz == 0 || sz == -1) {
			if(com == 0)
				continue;
			if(i == com) {
				printf("%l", i);
				l =+ 5;
			} else {
				printf("%l-%l", com, i);
				l =+ 10;
			}
			if(l > 60) {
				printf("\n");
				l = 0;
			} else
				printf(",");
			com = 0;
		} else
		if(com == 0)
			com = i+1;
	}
	if(com)
		printf("%l-\n", com);
	printf("\n");
	exit(0);

case 'r':
	if(argc <= 1) {
		printf("no filesystem name\n");
		exit(0);
	}
	ofile = argv[1];
	fo = open(ofile, 2);
	if(fo < 0) {
		printf("can not open %s\n", ofile);
		exit(0);
	}
	printf("last chance before scribbling on %s\n", ofile);
	rdline();
	dread(1, &sblock);
	tap = talist;
	for(i=0; i<sblock.s_isize; i++) {
		if(i >= isize)
			break;
		dread(i+2, buf);
		for(ip = &buf[0]; ip < &buf[256]; ip++) {
			sz = *tap++;
			if(sz == 0)
				continue;
			dealoc(ip);
			if(sz == -1) {
				for(p = ip; p < &ip->i_mtime[2]; )
					*p++ = 0;
				continue;
			}
			sread(dbuf, 0);
			q = dbuf;
			for(p = ip; p < &ip->i_mtime[2]; )
				*p++ = *q++;
			restor(ip, sz-1);
		}
		dwrite(i+2, buf);
	}
	dwrite(1, &sblock);
	com = 0;
	for(; i < isize; i++)
		for(l = 0; l < 16; l++) {
			sz = *tap++;
			if(sz != 0 && sz != -1)
				com++;
		}
	if(com)
		printf("%l files not restored - small ilist\n", com);
	exit(0);

case 'x':
	i = 0;
	tap = ilist;
	while(argc > 1) {
		i++;
		sz = number(argv[1]);
		argv++;
		argc--;
		if(sz <= 0 || sz >=isize*16) {
			printf("%l not in range\n", sz);
			continue;
		}
		if(talist[sz-1] == 0) {
			printf("%l not dumped\n", sz);
			continue;
		}
		if(talist[sz-1] == -1) {
			printf("%l does not exist\n", sz);
			continue;
		}
		*tap++ = sz;
	}
	if(i != 0 && ilist[0] == 0)
		exit(0);
	tap = talist;
	for(i=1; i<=isize*16; i++) {
		if(ilist[0] != 0) {
			for(sz=0; ilist[sz]; sz++)
				if(ilist[sz] == i)
					goto yes;
			sz = *tap++;
		no:
			if(sz == -1)
				sz = 0;
			while(sz--)
				tread(dbuf, 1);
			continue;
		}
	yes:
		sz = *tap++;
		if(sz == 0 || sz == -1)
			continue;
		fo = dwait(i);
		if(fo < 0)
			goto no;
		sz--;
		sread(buf, 0);
		ip = buf;
		while(sz--) {
			tread(dbuf, 0);
			com = 512;
			if(ip->i_size0 == 0 && ip->i_size1 < 512)
				com = ip->i_size1;
			write(fo, dbuf, com);
			if(com > ip->i_size1)
				ip->i_size0--;
			ip->i_size1 =- com;
		}
		close(fo);
		chmod(file, ip->i_mode);
		chown(file, ip->i_uid);
	}
	exit(0);

	}
}

dealoc(p)
struct inode *p;
{
	register struct inode *ip;
	register i, j;
	int k;
	int xbuf[256], ybuf[256];

	ip = p;
	if(ip->i_mode & (IFCHR&IFBLK))
		return;
	for(i=7; i>=0; i--)
	if(ip->i_addr[i]) {
		if(ip->i_mode&ILARG) {
			dread(ip->i_addr[i], xbuf);
			for(j=255; j>=0; j--)
			if(xbuf[j]) {
				/* this section for huge files */
				/*if(i == 7) {
					dread(xbuf[j], ybuf);
					for(k=255; k>=0; k--)
					if(ybuf[k])
						free(ybuf[k]);
				}*/
				free(xbuf[j]);
			}
		}
		free(ip->i_addr[i]);
	}
}

restor(p, sz)
struct inode *p;
{
	register struct inode *ip;
	register i, j;
	int xbuf[256];

	ip = p;
	if(ip->i_mode & (IFCHR&IFBLK))
		return;
	for(i=0; i<8; i++)
		ip->i_addr[i] = 0;
	if(sz <= 8) {
		for(i=0; i<sz; i++)
			ip->i_addr[i] = rcop();
		ip->i_mode =& ~ILARG;
		return;
	}
	for(i=0; i<256; i++)
		xbuf[i] = 0;
	for(j=0; sz >= 256; j++) {
		/*if(j <= 7)				huge*/
			ip->i_addr[j] = alloc();
		/*if(j >= 7)				huge*/
			/*xbuf[j-7] = alloc();		huge*/
		for(i=0; i<256; i++)
			dbuf[i] = rcop();
		/*if(j < 7)				huge*/
			dwrite(ip->i_addr[j], dbuf);
			/*else dwrite(xbuf[j-7], dbuf); huge*/
		sz =- 256;
	}
	if(sz) {
		/*if(j <= 7)				huge*/
			ip->i_addr[j] = alloc();
		/*if(j >= 7)				huge*/
			/*xbuf[j-7] = alloc();		huge*/
		for(i=0; i<sz; i++)
			dbuf[i] = rcop();
		for(; i<256; i++)
			dbuf[i] = 0;
		/*if(j < 7)				huge*/
			dwrite(ip->i_addr[j], dbuf);
			/*else dwrite(xbuf[j-7], dbuf);	huge*/
	}
	/*if(j >= 7)					huge*/
		/*dwrite(ip->i_addr[7], xbuf);		huge*/
	ip->i_mode =| ILARG;
}

rcop()
{
	register b;

	b = alloc();
	tread(cbuf, 0);
	dwrite(b, cbuf);
	return(b);
}

pdate(d)
int *d;
{

	if(d[0] == 0 && d[1] == 0)
		printf("the epoch\n"); else
		printf(ctime(d));
}

dread(bno, b)
{

	seek(fo, bno, 3);
	if(read(fo, b, 512) != 512) {
		printf("disk read error %l\n", bno);
		exit(0);
	}
}

dwrite(bno, b)
{

	seek(fo, bno, 3);
	if(write(fo, b, 512) != 512) {
		printf("disk write error %l\n", bno);
		exit(0);
	}
}

sread(b, flag)
int *b;
{
	register i, s, *p;

	tread(b, flag);
	if(flag)
		return;
	i = 256;
	s = 0;
	p = b;
	while(i--)
		s =+ *p++;
	if(s != 031415) {
		printf("checksum error\n");
		if(!iflg)
			exit(0);
	}
}

tread(b, flag)
int *b;
{
	register c;
	static char *pta, *ctflg, *ntape;
	static int tapeno;
	int *p, pt;

	if(pta++ >= recsiz) {
		pta = 1;
		ctflg++;
		ntape++;
		if(ntape == tsize){
			ctflg = 1;
			ntape = 1;
			tapeno++;
		}
	}
	if(flag)
		return;
	if(ctflg) {
		rawin(ctflg,tapeno,ntape);
		ctflg = 0;
		tapeno = 0;
	}
	pt = pta;
	p = bigbuf + (pt - 1)*256;
	for(pt = 0;pt < 256;pt++)
		*b++ = *p++;
}
rawin(ctflg,tapeno,ntape)
char *ctflg;
{
	register *b, i;
	int c;
	if(tapeno){
		printf("change tapes\n");
		if(tapeno > 1)
			printf("skip %d tapes\n",tapeno-1);
		close(fi);
		if (!cflg)
			rdline();
		otape(0);
	}
	for(i = ctflg-1;i > 0;i--){
		if(read(fi, bigbuf, bufsiz) != bufsiz)
			printf("read error at record %l\n",ntape);
	}
	if(read(fi, bigbuf, bufsiz) != bufsiz) {
		printf("read error at record %l\n",ntape);
		if(!iflg)
			exit(0);
	}
}

number(s)
char *s;
{
	register n, c;

	n = 0;
	while(c = *s++) {
		if(c<'0' || c>'9')
			continue;
		n = n*10+c-'0';
	}
	return(n);
}

size(s0, s1)
{
	register s;
	extern ldivr;

	s = ldiv(s0&0377, s1, 512);
	if(ldivr)
		s++;
	return(s);
}

otape(flg)
{
	register char *p;

	while((	fi = open(ifile, 0)) < 0){
		printf("can not open %s\n", ifile);
		rdline();
	}
	if(!cflg || flg)
		return;
	p = ifile;
	while(*p++)
		;
	p[-2]++;
}

rdline()
{
	char c;
	while(read(0,&c,1) != '\0'){
		if(c == '\n')
			return;
	}
	exit(0);
}
dwait(ino)
{
	register i, yflg;
	dconv(ino, file);
	if(wflg){
		printf("%s ",file);
		while((i = getchar()) != '\n'){
			if(i == 'y') yflg++;
			if(i == 'x') exit(0);
		}
		if(yflg)
			return(creat(file, 0666));
		else return(-1);
	}
	return(creat(file, 0666));
}

dconv(n, p)
char *p;
{
	register i;

	if(i = ldiv(0, n, 10))
		p = dconv(i, p);
	*p++ = lrem(0, n, 10) + '0';
	*p = '\0';
	return(p);
}

alloc()
{
	register b, i;

	i = --sblock.s_nfree;
	if(i<0 || i>=100) {
		printf("bad freeblock\n");
		exit(0);
	}
	b = sblock.s_free[i];
	if(b == 0) {
		printf("out of freelist\n");
		exit(0);
	}
	if(sblock.s_nfree <= 0) {
		dread(b, cbuf);
		sblock.s_nfree = cbuf[0];
		for(i=0; i<100; i++)
			sblock.s_free[i] = cbuf[i+1];
	}
	return(b);
}

free(in)
{
	register i;

	if(sblock.s_nfree >= 100) {
		cbuf[0] = sblock.s_nfree;
		for(i=0; i<100; i++)
			cbuf[i+1] = sblock.s_free[i];
		sblock.s_nfree = 0;
		dwrite(in, cbuf);
	}
	sblock.s_free[sblock.s_nfree++] = in;
}
