#

/*
 * incremental dump
 * dump isuodh filesystem
 * i from date in /etc/ddate
 * s specify tape size in feet (feet = blocks/9)
 * u update /etc/ddate to current date
 * 0 dump from the epoch
 * d dump specified number of days
 * h dump specified number of hours
 */

char	*dargv[]
{
	0,
	"i",
	"/dev/rp0",
	0
};
char	*dfile	"/etc/ddate";
char	*ofile	"/dev/mt0";
struct	inode
{
	int	i_mode;
	char	i_nlink;
	char	i_uid;
	char	i_gid;
	char	i_size0;
	char	*i_size1;
	int	i_addr[8];
	int	i_atime[2];
	int	i_mtime[2];
};

/* modes */
#define	IALLOC	0100000
#define	IFMT	060000
#define		IFDIR	040000
#define		IFCHR	020000
#define		IFBLK	060000
#define	ILARG	010000

struct
{
	char	*s_isize;
	char	*s_fsize;
	int	s_nfree;
	int	s_free[100];
	int	s_ninode;
	int	s_inode[100];
	char	s_flock;
	char	s_ilock;
	char	s_fmod;
	int	time[2];
	int	pad[50];
} sblock;

int	*talist;
int	fi;
int	buf[256];
int	dbuf[256];
int	ibuf[256];
char	*date[2];
char	*ddate[2];
int	fo;
int	pher;
int	dflg;
char	*tsize	15000;

main(argc, argv)
char **argv;
{
	char *key;
	int s, i, nfil, nblk;
	register *tap;
	register struct inode *ip;

	time(date);
	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();

	case 'i':
		i = open(dfile, 0);
		if(i >= 0) {
			read(i, ddate, 4);
			close(i);
		}
		continue;

	case 's': /* tape size */
		tsize = number(argv[1]) * 9;
		argv++;
		argc--;
		continue;

	case 'u': /* rewrite date */
		dflg++;
		continue;

	case '0': /* dump all */
		ddate[0] = ddate[1] = 0;
		continue;

	case 'd': /* dump some number of days */
		i = 21600;
		goto sd;

	case 'h': /* dump some number of hours */
		i = 900;
		goto sd;

	sd:
		ddate[0] = date[0];
		ddate[1] = date[1];
		s = number(argv[1])*4;
		argv++;
		argc--;
		while(s) {
			if(i > ddate[1])
				ddate[0]--;
			ddate[1] =- i;
			s--;
		}
		continue;
	}
	if(argc <= 1) {
		printf("no file system specified\n");
		exit();
	}
	printf("%s:\n", argv[1]);
	fi = open(argv[1], 0);
	if(fi < 0) {
		printf("cannot open %s\n", argv[1]);
		exit();
	}
	printf("incremental dump from\n");
	pdate(ddate);
	sync();
	bread(1, &sblock);
	talist = sbrk(size(0, sblock.s_isize*32)*512);
	tap = talist;
	nfil = 0;
	nblk = 0;
	for(i=0; i<sblock.s_isize; i++) {
		bread(i+2, buf);
		for(ip = &buf[0]; ip < &buf[256]; ip++) {
			if(ip->i_mode == 0)
				goto no;
			if(ip->i_nlink == 0)
				goto no;
			s = size(ip->i_size0, ip->i_size1);
			if(ip->i_mtime[0] < ddate[0])
				goto no;
			if(ip->i_mtime[0] == ddate[0] &&
			   ip->i_mtime[1] <  ddate[1])
				goto no;
			nfil++;
			nblk =+ s;
			*tap = s+1;
		no:
			tap++;
		}
	}
	printf("%l files\n%l blocks\n", nfil, nblk);
	otape();
	tap = buf;
	clrbuf(tap);
	*tap++ = sblock.s_isize;
	*tap++ = sblock.s_fsize;
	*tap++ = date[0];
	*tap++ = date[1];
	*tap++ = ddate[0];
	*tap++ = ddate[1];
	*tap++ = tsize;
	swrite(buf);
	i = size(0, sblock.s_isize*32);
	tap = talist;
	while(i--) {
		bwrite(tap);
		tap =+ 256;
	}
	tap = talist;
	for(i=0; i<sblock.s_isize; i++) {
		bread(i+2, buf);
		for(ip = &buf[0]; ip < &buf[256]; ip++) {
			if(*tap)
				dump(ip, *tap-1);
			tap++;
		}
	}
	printf("%l phase errors\n", pher);
	if(dflg) {
		i = open(dfile, 1);
		if(i >= 0) {
			write(i, date, 4);
			printf("date updated\n");
			pdate(date);
		}
	}
}

pdate(d)
int *d;
{

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

dump(ip, sz)
struct inode *ip;
{
	register *p, *q;

	p = dbuf;
	q = ip;
	clrbuf(p);
	while(q < &ip->i_mtime[2])
		*p++ = *q++;
	swrite(dbuf);
	if(ip->i_mode & (IFBLK&IFCHR)) {
		if(sz != 0)
			printf("special\n");
		return;
	}
	for(p = &ip->i_addr[0]; p < &ip->i_addr[8]; p++) {
		if(*p == 0)
			continue;
		if(ip->i_mode&ILARG) {
			bread(*p, ibuf);
			for(q = &ibuf[0]; q < &ibuf[256]; q++) {
				if(*q == 0)
					continue;
				if(--sz < 0)
					goto pe;
				bread(*q, dbuf);
				bwrite(dbuf);
			}
		} else {
			if(--sz < 0)
				goto pe;
			bread(*p, dbuf);
			bwrite(dbuf);
		}
	}
	if(sz)
		goto pe;
	return;

pe:
	clrbuf(dbuf);
	while(--sz >= 0)
		bwrite(dbuf);
	pher++;
}

bread(bno, b)
{

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

clrbuf(b)
int *b;
{
	register i, *p;

	p = b;
	i = 256;
	while(i--)
		*p++ = 0;
}

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

	i = 255;
	s = 0;
	p = b;
	while(i--)
		s =+ *p++;
	*p = 031415 - s;
	bwrite(b);
}

bwrite(b)
{
	static char *ta;

	if(ta++ > tsize) {
		printf("change tapes\n");
		close(fo);
		while((ta = getchar()) != '\n')
			if(ta == 0)
				exit();
		ta = 0;
		otape();
	}
	if(write(fo, b, 512) != 512) {
		printf("write error\n");
		exit();
	}
}

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()
{
	fo = open(ofile, 1);
	if(fo < 0) {
		printf("can not open %s\n", ofile);
		exit();
	}
}
