V10/cmd/worm/wbtree.c

Compare this file to the similar file:
Show the results in this format:

#include	<libc.h>
#include	"worm.h"
#include	"sym.h"
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<fio.h>

Inode **inos;
long nino;
int fdT, fdF;
char *inonames;
char *timenow();
char *tmp = "/tmp";

cmp(a, b)
	Inode **a, **b;
{
	return(strcmp((*a)->name.n, (*b)->name.n));
}

main(argc, argv)
	char **argv;
{
	Superblock s, news;
	char *e;
	char *dev = "/dev/worm0";
	int c, fd;
	char dbname[256];
	extern char *optarg;
	extern int optind;
	void blkfn();

	while((c = getopt(argc, argv, "t:f:")) != -1)
		switch(c)
		{
		case 'f':	dev = optarg; break;
		case 't':	tmp = optarg; break;
		case '?':	usage();
		}
	dev = mapdev(dev);
	if(optind != argc-1)
		usage();
	sprint(dbname, "%s/cbt%d", tmp, getpid());
	fd = dbinit(dbname);
	if((s.fd = open(dev, 2)) < 0){
		perror(dev);
		exit(1);
	}
	if(e = openinode(&s, DO_INODE|SPIN_DOWN)){
		fprint(2, "%s: %s\n", dev, e);
		exit(1);
	}
	if(strcmp(argv[optind], s.vol_id)){
		fprint(2, "wanted volid '%s'; got '%s'\n", argv[optind], s.vol_id);
		exit(1);
	}
	if((inos = (Inode **)malloc(sizeof(inos[0])*(int)numinodes)) == 0){
		fprint(2, "out of memory (%d inodes, %d bytes)\n", numinodes, sizeof(inos[0])*(int)numinodes);
		exit(1);
	}
	nino = 0;
	inodetraverse(blkfn);
	fprint(2, "%s: sorting inodes\n", timenow());
	qsort((char *)inos, (int)nino, sizeof(inos[0]), cmp);
	news = s;
	news.ninodes = nino;
	creatdb(fd, dbname, &news);	/* fills in nF, nT, inochars */
	c = NBLKS(&news, news.nF)+NBLKS(&news, news.nT)+NBLKS(&news, news.ninochars);
	if(c > news.nfree){
		fprint(2, "%s: sorry, not enough blocks; %d+%d+%d>%d\n", news.vol_id,
			NBLKS(&news, news.nF), NBLKS(&news, news.nT),
			NBLKS(&news, news.ninochars), news.nfree);
		exit(1);
	}
	Seek(&s, news.binodes = s.nextffree);
	fdwrite(&s, fdF, (int)news.nF);
	fdwrite(&s, fdT, (int)news.nT);
	memwrite(&s, inonames, (int)news.ninochars);
	/* set up link ptrs so that zeroing block zero undoes btreeing */
	s.nfree -= c;
	s.nextffree += c;
	s.ninodes = 0;
	if(e = lkwsb(&s))
		fprint(2, "%s\n", e);
	news.nextffree = s.nextffree;
	news.nfree = s.nfree;
	news.myblock = 0;
	news.version = VBTREE;
	news.nextsb = s.myblock;
	time(&news.ctime);
	Seek(&s, news.myblock);
	free((char *)inos);
	e = malloc(news.blocksize);
	if(e == 0){
		fprint(2, "wbtree: unbelievable malloc fail of %d\n", news.blocksize);
		exit(1);
	}
	memset(e, 0, news.blocksize);
	*((Superblock *)e) = news;
	Write(&s, e, 1L);
	exit(0);
}

usage()
{
	fprint(2, "Usage: worm btree [-fdevice] [-ttmpdir] vol_id\n");
	exit(2);
}

dbinit(name)
	char *name;
{
	char buf[256];
	struct stat sbuf;
	int pid, pip[2];

	fprint(2, "%s: init db '%s'\n", timenow(), name);
	sprint(buf, "cbt creat %s", name);
	if(system(buf))
		exit(1);
	pipe(pip);
	pid = fork();
	if(pid < 0){
		perror("fork");
		exit(1);
	}
	if(pid){
		close(pip[0]);
		return(pip[1]);
	} else {
		close(pip[1]);
		dup2(pip[0], 0);
		close(pip[0]);
		execl("/usr/lib/btree/btbuild", "btbuild", name, 0);
		perror("execl");
		exit(1);
		return(0);
	}
}

creatdb(fd, name, s)
	char *name;
	Superblock *s;	/* fills in nF, nT, inochars */
{
	char buf[256];
	struct stat sbuf;
	int status, i;
	short n;
	char *np;

	fprint(2, "%s: creating db '%s'\n", timenow(), name);
	inonames = malloc((int)numnamechars+1024);
	if(inonames == 0){
		sprint(buf, "malloc(%d) namechars failed", numnamechars+1024);
		perror(buf);
		exit(1);
	}
	Finit(fd, (char *)0);
	np = inonames;
	for(i = 0; i < nino; i++){
		n = strlen(inos[i]->name.n);
		Fwrite(fd, (char *)&n, 2L);
		Fwrite(fd, inos[i]->name.n, (long)n);
		memcpy(np, inos[i]->name.n, n+1);
		inos[i]->name.o = np - inonames;
		np += n+1;
		n = sizeof(Inode);
		Fwrite(fd, (char *)&n, 2L);
		Fwrite(fd, (char *)inos[i], (long)n);
	}
	s->ninochars = np-inonames;
	Fflush(fd);
	close(fd);
	if(wait(&status) < 0){
		perror("wbtree: wait");
		exit(1);
	}
	if(status){
		fprint(2, "wbtree: bad status %d from btbuild\n", status);
		exit(1);
	}
	sprint(buf, "%s.F", name);
	if(((fdF = open(buf, 0)) < 0) || (fstat(fdF, &sbuf) < 0)){
		perror(buf);
		exit(1);
	}
	unlink(buf);
	s->nF = sbuf.st_size;
	sprint(buf, "%s.T", name);
	if(((fdT = open(buf, 0)) < 0) || (fstat(fdT, &sbuf) < 0)){
		perror(buf);
		exit(1);
	}
	unlink(buf);
	s->nT = sbuf.st_size;
	fprint(2, "%s: db done\n", timenow());
}

void
blkfn(i)
	Inode *i;
{
	inos[nino++] = i;
}

fdwrite(s, fd, cnt)
	Superblock *s;
{
	char b[BIGBLOCK];
	int n;

	lseek(fd, 0L, 0);
	while(cnt >= sizeof b){
		n = read(fd, b, sizeof b);
		if(n != sizeof b){
			perror("short read");
			exit(3);
		}
		Write(s, b, NBLKS(s, sizeof b));
		cnt -= sizeof b;
	}
	if(cnt){
		if(read(fd, b, cnt) != cnt){
			perror("short read");
			exit(4);
		}
		memset(b+cnt, 0, sizeof b - cnt);
		Write(s, b, NBLKS(s, cnt));
	}
}

memwrite(s, base, cnt)
	Superblock *s;
	char *base;
{
	int chunk = (BIGBLOCK/1024)*s->blocksize;

	while(cnt >= chunk){
		Write(s, base, NBLKS(s, chunk));
		cnt -= chunk;
		base += chunk;
	}
	if(cnt)
		Write(s, base, NBLKS(s, cnt));
}

char *
timenow()
{
	long tim;
	char *tims;

	time(&tim);
	tims = ctime(&tim);
	tims[19] = 0;
	return(tims);
}