#include	<libc.h>
#include	<cbt.h>
#undef nfree
#include	"worm.h"
#include	"sym.h"
#include	<sys/types.h>
#include	<sys/stat.h>

static char *inonames;
static bfile *bf;
static dirlk(), wormdir();

char *
cbtinit(s, blk, doinodes)
	register Superblock *s;
	long blk;
{
	static char buf[64];
	char name[256], buf1[256];

	if(s->magic != SMAGIC){
		fprint(2, "bad Superblock at %ld\n", blk);
		exit(1);
	}
	numinodes = s->ninodes;
	if(doinodes){
		inonames = malloc(s->blocksize*(int)NBLKS(s, s->ninochars));
		if(inonames == 0){
			sprint(buf, "cbtinit: can't malloc %d\n", s->blocksize*(int)NBLKS(s, s->ninochars));
			return(buf);
		}
		if(dirlk(s) == 0)
			wormdir(s);
	} else
		inonames = 0;
	return((char *)0);
}

static
dirlk(s)
	register Superblock *s;
{
	char name[256], buf1[256];
	struct stat sbuf;
	int fd;

	sprint(name, "/usr/worm/dirs/%s", s->vol_id);
	sprint(buf1, "%s.I", name);
	if(stat(buf1, &sbuf) < 0)
		return(0);
	if(sbuf.st_mtime < s->ctime)
		return(0);	/* worm is more recent than disk */
	if((bf = bopen(name, 0)) == 0)
		return(0);
	sprint(buf1, "%s.I", name);
	if((fd = open(buf1, 0)) < 0){
		fprint(2, "%s: btree but no inodes\n", name);
		return(0);
	}
	if(read(fd, inonames, (int)s->ninochars) != s->ninochars){
		fprint(2, "%s: expected %d chars\n", buf1, s->ninochars);
		close(fd);
		return(0);
	}
	close(fd);
	return(1);
}

static
wormdir(s)
	register Superblock *s;
{
	char name[256], buf1[256];

	sprint(name, "/tmp/worm%d", getpid());
	Seek(s, s->binodes);
	sprint(buf1, "%s.F", name);
	copyout(s, buf1, s->nF, 0, 1);
	sprint(buf1, "%s.T", name);
	copyout(s, buf1, s->nT, 0, 1);
	if(Read(s, inonames, NBLKS(s, s->ninochars)))
		return(0);
	if((bf = bopen(name, 0)) == 0){
		fprint(2, "can't bopen %s", name);
		return(0);
	}
	sprint(buf1, "%s.F", name); unlink(buf1);
	sprint(buf1, "%s.T", name); unlink(buf1);
	return(1);
}

copyout(s, name, len, overwrite, verbose)
	register Superblock *s;
	char *name;
	long len;
{
	int fd, l;
	char *buf;

	if(access(name, 0) == 0){
		if(!overwrite){
			fprint(2, "%s already exists!\n", name);
			exit(1);
		}
		if(verbose)
			fprint(2, "overwriting %s\n", name);
	}
	if((fd = creat(name, 0666)) < 0){
		perror(name);
		exit(1);
	}
	if((buf = malloc(l = (BIGBLOCK/1024)*s->blocksize)) == 0){
		fprint(2, "can't malloc %d\n", l);
		exit(1);
	}
	if(verbose)
		print("%s: %d bytes\n", name, len);
	while(len >= l){
		if(Read(s, buf, NBLKS(s, l)))
			exit(1);
		if(write(fd, buf, l) != l){
			perror(name);
			exit(2);
		}
		len -= l;
	}
	if(Read(s, buf, NBLKS(s, len)))
		exit(2);
	if(write(fd, buf, (int)len) != len){
		perror(name);
		exit(2);
	}
	free(buf);
}

Inode *
binodefn(s)
	char *s;
{
	static Inode i;
	mbuf key;

	if(inonames == 0)
		return((Inode *)0);
	key.mdata = s;
	key.mlen = strlen(s);
	if(bseek(bf, key) != 1)
		return((Inode *)0);
	key.mdata = (char *)&i;
	if(bread(bf, (mbuf *)0, &key)){
		perror("inode read");
		return((Inode *)0);
	}
	i.name.n = i.name.o+inonames;
	return(&i);
}

void
btraverse(fn)
	void (*fn)();
{
	static Inode i;
	mbuf key;

	if(inonames == 0)
		return;
	bfirst(bf);
	key.mdata = (char *)&i;
	while(bread(bf, (mbuf *)0, &key) == 0){
		i.name.n = i.name.o+inonames;
		(*fn)(&i);
	}
}
