xref: /plan9-contrib/sys/src/cmd/fossil/flfmt.c (revision d7aba6c3b511bc618cf0c53345848188fc02611a)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier #include "dat.h"
35e96a66cSDavid du Colombier #include "fns.h"
4fe853e23SDavid du Colombier #include "flfmt9660.h"
55e96a66cSDavid du Colombier 
65e96a66cSDavid du Colombier #define blockWrite _blockWrite	/* hack */
75e96a66cSDavid du Colombier 
85e96a66cSDavid du Colombier static void usage(void);
95e96a66cSDavid du Colombier static u64int fdsize(int fd);
105e96a66cSDavid du Colombier static void partition(int fd, int bsize, Header *h);
115e96a66cSDavid du Colombier static u64int unittoull(char *s);
125e96a66cSDavid du Colombier static u32int blockAlloc(int type, u32int tag);
135e96a66cSDavid du Colombier static void blockRead(int part, u32int addr);
145e96a66cSDavid du Colombier static void blockWrite(int part, u32int addr);
157abd426fSDavid du Colombier static void superInit(char *label, u32int root, uchar[VtScoreSize]);
165e96a66cSDavid du Colombier static void rootMetaInit(Entry *e);
175e96a66cSDavid du Colombier static u32int rootInit(Entry *e);
185e96a66cSDavid du Colombier static void topLevel(char *name);
195e96a66cSDavid du Colombier static int parseScore(uchar[VtScoreSize], char*);
205e96a66cSDavid du Colombier static u32int ventiRoot(char*, char*);
21*d7aba6c3SDavid du Colombier static VtConn *z;
225e96a66cSDavid du Colombier 
235e96a66cSDavid du Colombier #define TWID64	((u64int)~(u64int)0)
245e96a66cSDavid du Colombier 
255e96a66cSDavid du Colombier Disk *disk;
265e96a66cSDavid du Colombier Fs *fs;
275e96a66cSDavid du Colombier uchar *buf;
285e96a66cSDavid du Colombier int bsize = 8*1024;
295e96a66cSDavid du Colombier u64int qid = 1;
30fe853e23SDavid du Colombier int iso9660off;
31fe853e23SDavid du Colombier char *iso9660file;
325e96a66cSDavid du Colombier 
335e96a66cSDavid du Colombier int
confirm(char * msg)345e96a66cSDavid du Colombier confirm(char *msg)
355e96a66cSDavid du Colombier {
365e96a66cSDavid du Colombier 	char buf[100];
375e96a66cSDavid du Colombier 	int n;
385e96a66cSDavid du Colombier 
395e96a66cSDavid du Colombier 	fprint(2, "%s [y/n]: ", msg);
405e96a66cSDavid du Colombier 	n = read(0, buf, sizeof buf - 1);
415e96a66cSDavid du Colombier 	if(n <= 0)
425e96a66cSDavid du Colombier 		return 0;
435e96a66cSDavid du Colombier 	if(buf[0] == 'y')
445e96a66cSDavid du Colombier 		return 1;
455e96a66cSDavid du Colombier 	return 0;
465e96a66cSDavid du Colombier }
475e96a66cSDavid du Colombier 
485e96a66cSDavid du Colombier void
threadmain(int argc,char * argv[])49*d7aba6c3SDavid du Colombier threadmain(int argc, char *argv[])
505e96a66cSDavid du Colombier {
515e96a66cSDavid du Colombier 	int fd, force;
525e96a66cSDavid du Colombier 	Header h;
535e96a66cSDavid du Colombier 	ulong bn;
545e96a66cSDavid du Colombier 	Entry e;
555e96a66cSDavid du Colombier 	char *label = "vfs";
565e96a66cSDavid du Colombier 	char *host = nil;
575e96a66cSDavid du Colombier 	char *score = nil;
585e96a66cSDavid du Colombier 	u32int root;
595e96a66cSDavid du Colombier 	Dir *d;
605e96a66cSDavid du Colombier 
615e96a66cSDavid du Colombier 	force = 0;
625e96a66cSDavid du Colombier 	ARGBEGIN{
635e96a66cSDavid du Colombier 	default:
645e96a66cSDavid du Colombier 		usage();
655e96a66cSDavid du Colombier 	case 'b':
665e96a66cSDavid du Colombier 		bsize = unittoull(EARGF(usage()));
675e96a66cSDavid du Colombier 		if(bsize == ~0)
685e96a66cSDavid du Colombier 			usage();
695e96a66cSDavid du Colombier 		break;
705e96a66cSDavid du Colombier 	case 'h':
715e96a66cSDavid du Colombier 		host = EARGF(usage());
725e96a66cSDavid du Colombier 		break;
73fe853e23SDavid du Colombier 	case 'i':
74fe853e23SDavid du Colombier 		iso9660file = EARGF(usage());
75fe853e23SDavid du Colombier 		iso9660off = atoi(EARGF(usage()));
76fe853e23SDavid du Colombier 		break;
775e96a66cSDavid du Colombier 	case 'l':
785e96a66cSDavid du Colombier 		label = EARGF(usage());
795e96a66cSDavid du Colombier 		break;
805e96a66cSDavid du Colombier 	case 'v':
815e96a66cSDavid du Colombier 		score = EARGF(usage());
825e96a66cSDavid du Colombier 		break;
835e96a66cSDavid du Colombier 
845e96a66cSDavid du Colombier 	/*
855e96a66cSDavid du Colombier 	 * This is -y instead of -f because flchk has a
865e96a66cSDavid du Colombier 	 * (frequently used) -f option.  I type flfmt instead
875e96a66cSDavid du Colombier 	 * of flchk all the time, and want to make it hard
885e96a66cSDavid du Colombier 	 * to reformat my file system accidentally.
895e96a66cSDavid du Colombier 	 */
905e96a66cSDavid du Colombier 	case 'y':
915e96a66cSDavid du Colombier 		force = 1;
925e96a66cSDavid du Colombier 		break;
935e96a66cSDavid du Colombier 	}ARGEND
945e96a66cSDavid du Colombier 
955e96a66cSDavid du Colombier 	if(argc != 1)
965e96a66cSDavid du Colombier 		usage();
975e96a66cSDavid du Colombier 
98fe853e23SDavid du Colombier 	if(iso9660file && score)
99*d7aba6c3SDavid du Colombier 		sysfatal("cannot use -i with -v");
1005e96a66cSDavid du Colombier 
1015e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
1025e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
1035e96a66cSDavid du Colombier 
1045e96a66cSDavid du Colombier 	fd = open(argv[0], ORDWR);
1055e96a66cSDavid du Colombier 	if(fd < 0)
106*d7aba6c3SDavid du Colombier 		sysfatal("could not open file: %s: %r", argv[0]);
1075e96a66cSDavid du Colombier 
108*d7aba6c3SDavid du Colombier 	buf = vtmallocz(bsize);
1095e96a66cSDavid du Colombier 	if(pread(fd, buf, bsize, HeaderOffset) != bsize)
110*d7aba6c3SDavid du Colombier 		sysfatal("could not read fs header block: %r");
1115e96a66cSDavid du Colombier 
1125e96a66cSDavid du Colombier 	if(headerUnpack(&h, buf) && !force
1135e96a66cSDavid du Colombier 	&& !confirm("fs header block already exists; are you sure?"))
1145e96a66cSDavid du Colombier 		goto Out;
1155e96a66cSDavid du Colombier 
1165e96a66cSDavid du Colombier 	if((d = dirfstat(fd)) == nil)
117*d7aba6c3SDavid du Colombier 		sysfatal("dirfstat: %r");
1185e96a66cSDavid du Colombier 
1195e96a66cSDavid du Colombier 	if(d->type == 'M' && !force
1205e96a66cSDavid du Colombier 	&& !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?"))
1215e96a66cSDavid du Colombier 		goto Out;
1225e96a66cSDavid du Colombier 
1235e96a66cSDavid du Colombier 	partition(fd, bsize, &h);
1245e96a66cSDavid du Colombier 	headerPack(&h, buf);
1255e96a66cSDavid du Colombier 	if(pwrite(fd, buf, bsize, HeaderOffset) < bsize)
126*d7aba6c3SDavid du Colombier 		sysfatal("could not write fs header: %r");
1275e96a66cSDavid du Colombier 
1285e96a66cSDavid du Colombier 	disk = diskAlloc(fd);
1295e96a66cSDavid du Colombier 	if(disk == nil)
130*d7aba6c3SDavid du Colombier 		sysfatal("could not open disk: %r");
1315e96a66cSDavid du Colombier 
132fe853e23SDavid du Colombier 	if(iso9660file)
133fe853e23SDavid du Colombier 		iso9660init(fd, &h, iso9660file, iso9660off);
134fe853e23SDavid du Colombier 
1355e96a66cSDavid du Colombier 	/* zero labels */
1365e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
1375e96a66cSDavid du Colombier 	for(bn = 0; bn < diskSize(disk, PartLabel); bn++)
1385e96a66cSDavid du Colombier 		blockWrite(PartLabel, bn);
1395e96a66cSDavid du Colombier 
140fe853e23SDavid du Colombier 	if(iso9660file)
141fe853e23SDavid du Colombier 		iso9660labels(disk, buf, blockWrite);
142fe853e23SDavid du Colombier 
1435e96a66cSDavid du Colombier 	if(score)
1445e96a66cSDavid du Colombier 		root = ventiRoot(host, score);
1455e96a66cSDavid du Colombier 	else{
1465e96a66cSDavid du Colombier 		rootMetaInit(&e);
1475e96a66cSDavid du Colombier 		root = rootInit(&e);
1485e96a66cSDavid du Colombier 	}
1495e96a66cSDavid du Colombier 
150*d7aba6c3SDavid du Colombier 	superInit(label, root, vtzeroscore);
1515e96a66cSDavid du Colombier 	diskFree(disk);
1525e96a66cSDavid du Colombier 
153e6c6b7f8SDavid du Colombier 	if(score == nil)
1545e96a66cSDavid du Colombier 		topLevel(argv[0]);
1555e96a66cSDavid du Colombier 
1565e96a66cSDavid du Colombier Out:
157*d7aba6c3SDavid du Colombier 	threadexitsall(0);
1585e96a66cSDavid du Colombier }
1595e96a66cSDavid du Colombier 
1605e96a66cSDavid du Colombier static u64int
fdsize(int fd)1615e96a66cSDavid du Colombier fdsize(int fd)
1625e96a66cSDavid du Colombier {
1635e96a66cSDavid du Colombier 	Dir *dir;
1645e96a66cSDavid du Colombier 	u64int size;
1655e96a66cSDavid du Colombier 
1665e96a66cSDavid du Colombier 	dir = dirfstat(fd);
1675e96a66cSDavid du Colombier 	if(dir == nil)
168*d7aba6c3SDavid du Colombier 		sysfatal("could not stat file: %r");
1695e96a66cSDavid du Colombier 	size = dir->length;
1705e96a66cSDavid du Colombier 	free(dir);
1715e96a66cSDavid du Colombier 	return size;
1725e96a66cSDavid du Colombier }
1735e96a66cSDavid du Colombier 
1745e96a66cSDavid du Colombier static void
usage(void)1755e96a66cSDavid du Colombier usage(void)
1765e96a66cSDavid du Colombier {
1770c6300e7SDavid du Colombier 	fprint(2, "usage: %s [-b blocksize] [-h host] [-i file offset] "
1780c6300e7SDavid du Colombier 		"[-l label] [-v score] [-y] file\n", argv0);
179*d7aba6c3SDavid du Colombier 	threadexitsall("usage");
1805e96a66cSDavid du Colombier }
1815e96a66cSDavid du Colombier 
1825e96a66cSDavid du Colombier static void
partition(int fd,int bsize,Header * h)1835e96a66cSDavid du Colombier partition(int fd, int bsize, Header *h)
1845e96a66cSDavid du Colombier {
1855e96a66cSDavid du Colombier 	ulong nblock, ndata, nlabel;
1865e96a66cSDavid du Colombier 	ulong lpb;
1875e96a66cSDavid du Colombier 
1885e96a66cSDavid du Colombier 	if(bsize % 512 != 0)
1895e96a66cSDavid du Colombier 		sysfatal("block size must be a multiple of 512 bytes");
1905e96a66cSDavid du Colombier 	if(bsize > VtMaxLumpSize)
1915e96a66cSDavid du Colombier 		sysfatal("block size must be less than %d", VtMaxLumpSize);
1925e96a66cSDavid du Colombier 
1935e96a66cSDavid du Colombier 	memset(h, 0, sizeof(*h));
1945e96a66cSDavid du Colombier 	h->blockSize = bsize;
1955e96a66cSDavid du Colombier 
1965e96a66cSDavid du Colombier 	lpb = bsize/LabelSize;
1975e96a66cSDavid du Colombier 
1985e96a66cSDavid du Colombier 	nblock = fdsize(fd)/bsize;
1995e96a66cSDavid du Colombier 
2005e96a66cSDavid du Colombier 	/* sanity check */
2015e96a66cSDavid du Colombier 	if(nblock < (HeaderOffset*10)/bsize)
202*d7aba6c3SDavid du Colombier 		sysfatal("file too small");
2035e96a66cSDavid du Colombier 
2045e96a66cSDavid du Colombier 	h->super = (HeaderOffset + 2*bsize)/bsize;
2055e96a66cSDavid du Colombier 	h->label = h->super + 1;
2065e96a66cSDavid du Colombier 	ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1);
2075e96a66cSDavid du Colombier 	nlabel = (ndata + lpb - 1)/lpb;
2085e96a66cSDavid du Colombier 	h->data = h->label + nlabel;
2095e96a66cSDavid du Colombier 	h->end = h->data + ndata;
2105e96a66cSDavid du Colombier 
2115e96a66cSDavid du Colombier }
2125e96a66cSDavid du Colombier 
2135e96a66cSDavid du Colombier static u32int
tagGen(void)2145e96a66cSDavid du Colombier tagGen(void)
2155e96a66cSDavid du Colombier {
2165e96a66cSDavid du Colombier 	u32int tag;
2175e96a66cSDavid du Colombier 
2185e96a66cSDavid du Colombier 	for(;;){
2195e96a66cSDavid du Colombier 		tag = lrand();
2205e96a66cSDavid du Colombier 		if(tag > RootTag)
2215e96a66cSDavid du Colombier 			break;
2225e96a66cSDavid du Colombier 	}
2235e96a66cSDavid du Colombier 	return tag;
2245e96a66cSDavid du Colombier }
2255e96a66cSDavid du Colombier 
2265e96a66cSDavid du Colombier static void
entryInit(Entry * e)2275e96a66cSDavid du Colombier entryInit(Entry *e)
2285e96a66cSDavid du Colombier {
2295e96a66cSDavid du Colombier 	e->gen = 0;
2305e96a66cSDavid du Colombier 	e->dsize = bsize;
2315e96a66cSDavid du Colombier 	e->psize = bsize/VtEntrySize*VtEntrySize;
2325e96a66cSDavid du Colombier 	e->flags = VtEntryActive;
2335e96a66cSDavid du Colombier 	e->depth = 0;
2345e96a66cSDavid du Colombier 	e->size = 0;
235*d7aba6c3SDavid du Colombier 	memmove(e->score, vtzeroscore, VtScoreSize);
2365e96a66cSDavid du Colombier 	e->tag = tagGen();
2375e96a66cSDavid du Colombier 	e->snap = 0;
2385e96a66cSDavid du Colombier 	e->archive = 0;
2395e96a66cSDavid du Colombier }
2405e96a66cSDavid du Colombier 
2415e96a66cSDavid du Colombier static void
rootMetaInit(Entry * e)2425e96a66cSDavid du Colombier rootMetaInit(Entry *e)
2435e96a66cSDavid du Colombier {
2445e96a66cSDavid du Colombier 	u32int addr;
2455e96a66cSDavid du Colombier 	u32int tag;
2465e96a66cSDavid du Colombier 	DirEntry de;
2475e96a66cSDavid du Colombier 	MetaBlock mb;
2485e96a66cSDavid du Colombier 	MetaEntry me;
2495e96a66cSDavid du Colombier 
2505e96a66cSDavid du Colombier 	memset(&de, 0, sizeof(de));
251*d7aba6c3SDavid du Colombier 	de.elem = vtstrdup("root");
2525e96a66cSDavid du Colombier 	de.entry = 0;
2535e96a66cSDavid du Colombier 	de.gen = 0;
2545e96a66cSDavid du Colombier 	de.mentry = 1;
2555e96a66cSDavid du Colombier 	de.mgen = 0;
2565e96a66cSDavid du Colombier 	de.size = 0;
2575e96a66cSDavid du Colombier 	de.qid = qid++;
258*d7aba6c3SDavid du Colombier 	de.uid = vtstrdup("adm");
259*d7aba6c3SDavid du Colombier 	de.gid = vtstrdup("adm");
260*d7aba6c3SDavid du Colombier 	de.mid = vtstrdup("adm");
2615e96a66cSDavid du Colombier 	de.mtime = time(0);
2625e96a66cSDavid du Colombier 	de.mcount = 0;
2635e96a66cSDavid du Colombier 	de.ctime = time(0);
2645e96a66cSDavid du Colombier 	de.atime = time(0);
2655e96a66cSDavid du Colombier 	de.mode = ModeDir | 0555;
2665e96a66cSDavid du Colombier 
2675e96a66cSDavid du Colombier 	tag = tagGen();
2685e96a66cSDavid du Colombier 	addr = blockAlloc(BtData, tag);
2695e96a66cSDavid du Colombier 
2705e96a66cSDavid du Colombier 	/* build up meta block */
2715e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
2725e96a66cSDavid du Colombier 	mbInit(&mb, buf, bsize, bsize/100);
2735e96a66cSDavid du Colombier 	me.size = deSize(&de);
2745e96a66cSDavid du Colombier 	me.p = mbAlloc(&mb, me.size);
2755e96a66cSDavid du Colombier 	assert(me.p != nil);
2765e96a66cSDavid du Colombier 	dePack(&de, &me);
2775e96a66cSDavid du Colombier 	mbInsert(&mb, 0, &me);
2785e96a66cSDavid du Colombier 	mbPack(&mb);
2795e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
2805e96a66cSDavid du Colombier 	deCleanup(&de);
2815e96a66cSDavid du Colombier 
2825e96a66cSDavid du Colombier 	/* build up entry for meta block */
2835e96a66cSDavid du Colombier 	entryInit(e);
2845e96a66cSDavid du Colombier 	e->flags |= VtEntryLocal;
2855e96a66cSDavid du Colombier  	e->size = bsize;
2865e96a66cSDavid du Colombier 	e->tag = tag;
2875e96a66cSDavid du Colombier 	localToGlobal(addr, e->score);
2885e96a66cSDavid du Colombier }
2895e96a66cSDavid du Colombier 
2905e96a66cSDavid du Colombier static u32int
rootInit(Entry * e)2915e96a66cSDavid du Colombier rootInit(Entry *e)
2925e96a66cSDavid du Colombier {
2935e96a66cSDavid du Colombier 	ulong addr;
2945e96a66cSDavid du Colombier 	u32int tag;
2955e96a66cSDavid du Colombier 
2965e96a66cSDavid du Colombier 	tag = tagGen();
2975e96a66cSDavid du Colombier 
2985e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, tag);
2995e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3005e96a66cSDavid du Colombier 
3015e96a66cSDavid du Colombier 	/* root meta data is in the third entry */
3025e96a66cSDavid du Colombier 	entryPack(e, buf, 2);
3035e96a66cSDavid du Colombier 
3045e96a66cSDavid du Colombier 	entryInit(e);
305*d7aba6c3SDavid du Colombier 	e->flags |= _VtEntryDir;
3065e96a66cSDavid du Colombier 	entryPack(e, buf, 0);
3075e96a66cSDavid du Colombier 
3085e96a66cSDavid du Colombier 	entryInit(e);
3095e96a66cSDavid du Colombier 	entryPack(e, buf, 1);
3105e96a66cSDavid du Colombier 
3115e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
3125e96a66cSDavid du Colombier 
3135e96a66cSDavid du Colombier 	entryInit(e);
314*d7aba6c3SDavid du Colombier 	e->flags |= VtEntryLocal|_VtEntryDir;
3155e96a66cSDavid du Colombier  	e->size = VtEntrySize*3;
3165e96a66cSDavid du Colombier 	e->tag = tag;
3175e96a66cSDavid du Colombier 	localToGlobal(addr, e->score);
3185e96a66cSDavid du Colombier 
3195e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, RootTag);
3205e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3215e96a66cSDavid du Colombier 	entryPack(e, buf, 0);
3225e96a66cSDavid du Colombier 
3235e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
3245e96a66cSDavid du Colombier 
3255e96a66cSDavid du Colombier 	return addr;
3265e96a66cSDavid du Colombier }
3275e96a66cSDavid du Colombier 
3285e96a66cSDavid du Colombier 
3295e96a66cSDavid du Colombier static u32int
blockAlloc(int type,u32int tag)3305e96a66cSDavid du Colombier blockAlloc(int type, u32int tag)
3315e96a66cSDavid du Colombier {
3325e96a66cSDavid du Colombier 	static u32int addr;
3335e96a66cSDavid du Colombier 	Label l;
3345e96a66cSDavid du Colombier 	int lpb;
3355e96a66cSDavid du Colombier 
3365e96a66cSDavid du Colombier 	lpb = bsize/LabelSize;
3375e96a66cSDavid du Colombier 
3385e96a66cSDavid du Colombier 	blockRead(PartLabel, addr/lpb);
339fe853e23SDavid du Colombier 	if(!labelUnpack(&l, buf, addr % lpb))
340*d7aba6c3SDavid du Colombier 		sysfatal("bad label: %r");
341fe853e23SDavid du Colombier 	if(l.state != BsFree)
342*d7aba6c3SDavid du Colombier 		sysfatal("want to allocate block already in use");
3435e96a66cSDavid du Colombier 	l.epoch = 1;
3445e96a66cSDavid du Colombier 	l.epochClose = ~(u32int)0;
3455e96a66cSDavid du Colombier 	l.type = type;
3465e96a66cSDavid du Colombier 	l.state = BsAlloc;
3475e96a66cSDavid du Colombier 	l.tag = tag;
3485e96a66cSDavid du Colombier 	labelPack(&l, buf, addr % lpb);
3495e96a66cSDavid du Colombier 	blockWrite(PartLabel, addr/lpb);
3505e96a66cSDavid du Colombier 	return addr++;
3515e96a66cSDavid du Colombier }
3525e96a66cSDavid du Colombier 
3535e96a66cSDavid du Colombier static void
superInit(char * label,u32int root,uchar score[VtScoreSize])3547abd426fSDavid du Colombier superInit(char *label, u32int root, uchar score[VtScoreSize])
3555e96a66cSDavid du Colombier {
3565e96a66cSDavid du Colombier 	Super s;
3575e96a66cSDavid du Colombier 
3585e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3595e96a66cSDavid du Colombier 	memset(&s, 0, sizeof(s));
3605e96a66cSDavid du Colombier 	s.version = SuperVersion;
3615e96a66cSDavid du Colombier 	s.epochLow = 1;
3625e96a66cSDavid du Colombier 	s.epochHigh = 1;
3635e96a66cSDavid du Colombier 	s.qid = qid;
3645e96a66cSDavid du Colombier 	s.active = root;
3655e96a66cSDavid du Colombier 	s.next = NilBlock;
3665e96a66cSDavid du Colombier 	s.current = NilBlock;
3675e96a66cSDavid du Colombier 	strecpy(s.name, s.name+sizeof(s.name), label);
3687abd426fSDavid du Colombier 	memmove(s.last, score, VtScoreSize);
3695e96a66cSDavid du Colombier 
3705e96a66cSDavid du Colombier 	superPack(&s, buf);
3715e96a66cSDavid du Colombier 	blockWrite(PartSuper, 0);
3725e96a66cSDavid du Colombier }
3735e96a66cSDavid du Colombier 
3745e96a66cSDavid du Colombier static u64int
unittoull(char * s)3755e96a66cSDavid du Colombier unittoull(char *s)
3765e96a66cSDavid du Colombier {
3775e96a66cSDavid du Colombier 	char *es;
3785e96a66cSDavid du Colombier 	u64int n;
3795e96a66cSDavid du Colombier 
3805e96a66cSDavid du Colombier 	if(s == nil)
3815e96a66cSDavid du Colombier 		return TWID64;
3825e96a66cSDavid du Colombier 	n = strtoul(s, &es, 0);
3835e96a66cSDavid du Colombier 	if(*es == 'k' || *es == 'K'){
3845e96a66cSDavid du Colombier 		n *= 1024;
3855e96a66cSDavid du Colombier 		es++;
3865e96a66cSDavid du Colombier 	}else if(*es == 'm' || *es == 'M'){
3875e96a66cSDavid du Colombier 		n *= 1024*1024;
3885e96a66cSDavid du Colombier 		es++;
3895e96a66cSDavid du Colombier 	}else if(*es == 'g' || *es == 'G'){
3905e96a66cSDavid du Colombier 		n *= 1024*1024*1024;
3915e96a66cSDavid du Colombier 		es++;
3925e96a66cSDavid du Colombier 	}
3935e96a66cSDavid du Colombier 	if(*es != '\0')
3945e96a66cSDavid du Colombier 		return TWID64;
3955e96a66cSDavid du Colombier 	return n;
3965e96a66cSDavid du Colombier }
3975e96a66cSDavid du Colombier 
3985e96a66cSDavid du Colombier static void
blockRead(int part,u32int addr)3995e96a66cSDavid du Colombier blockRead(int part, u32int addr)
4005e96a66cSDavid du Colombier {
4015e96a66cSDavid du Colombier 	if(!diskReadRaw(disk, part, addr, buf))
402*d7aba6c3SDavid du Colombier 		sysfatal("read failed: %r");
4035e96a66cSDavid du Colombier }
4045e96a66cSDavid du Colombier 
4055e96a66cSDavid du Colombier static void
blockWrite(int part,u32int addr)4065e96a66cSDavid du Colombier blockWrite(int part, u32int addr)
4075e96a66cSDavid du Colombier {
4085e96a66cSDavid du Colombier 	if(!diskWriteRaw(disk, part, addr, buf))
409*d7aba6c3SDavid du Colombier 		sysfatal("write failed: %r");
4105e96a66cSDavid du Colombier }
4115e96a66cSDavid du Colombier 
4125e96a66cSDavid du Colombier static void
addFile(File * root,char * name,uint mode)4135e96a66cSDavid du Colombier addFile(File *root, char *name, uint mode)
4145e96a66cSDavid du Colombier {
4155e96a66cSDavid du Colombier 	File *f;
4165e96a66cSDavid du Colombier 
4175e96a66cSDavid du Colombier 	f = fileCreate(root, name, mode | ModeDir, "adm");
4185e96a66cSDavid du Colombier 	if(f == nil)
419*d7aba6c3SDavid du Colombier 		sysfatal("could not create file: %s: %r", name);
4205e96a66cSDavid du Colombier 	fileDecRef(f);
4215e96a66cSDavid du Colombier }
4225e96a66cSDavid du Colombier 
4235e96a66cSDavid du Colombier static void
topLevel(char * name)4245e96a66cSDavid du Colombier topLevel(char *name)
4255e96a66cSDavid du Colombier {
4265e96a66cSDavid du Colombier 	Fs *fs;
4275e96a66cSDavid du Colombier 	File *root;
4285e96a66cSDavid du Colombier 
4295e96a66cSDavid du Colombier 	/* ok, now we can open as a fs */
4305e96a66cSDavid du Colombier 	fs = fsOpen(name, z, 100, OReadWrite);
4315e96a66cSDavid du Colombier 	if(fs == nil)
432*d7aba6c3SDavid du Colombier 		sysfatal("could not open file system: %r");
433*d7aba6c3SDavid du Colombier 	rlock(&fs->elk);
4345e96a66cSDavid du Colombier 	root = fsGetRoot(fs);
4355e96a66cSDavid du Colombier 	if(root == nil)
436*d7aba6c3SDavid du Colombier 		sysfatal("could not open root: %r");
437c3c4501eSDavid du Colombier 	addFile(root, "active", 0555);
4385e96a66cSDavid du Colombier 	addFile(root, "archive", 0555);
4395e96a66cSDavid du Colombier 	addFile(root, "snapshot", 0555);
4405e96a66cSDavid du Colombier 	fileDecRef(root);
441fe853e23SDavid du Colombier 	if(iso9660file)
442fe853e23SDavid du Colombier 		iso9660copy(fs);
443*d7aba6c3SDavid du Colombier 	runlock(&fs->elk);
4445e96a66cSDavid du Colombier 	fsClose(fs);
4455e96a66cSDavid du Colombier }
4465e96a66cSDavid du Colombier 
4475e96a66cSDavid du Colombier static int
ventiRead(uchar score[VtScoreSize],int type)4485e96a66cSDavid du Colombier ventiRead(uchar score[VtScoreSize], int type)
4495e96a66cSDavid du Colombier {
4505e96a66cSDavid du Colombier 	int n;
4515e96a66cSDavid du Colombier 
452*d7aba6c3SDavid du Colombier 	n = vtread(z, score, type, buf, bsize);
4535e96a66cSDavid du Colombier 	if(n < 0)
454*d7aba6c3SDavid du Colombier 		sysfatal("ventiRead %V (%d) failed: %r", score, type);
455*d7aba6c3SDavid du Colombier 	vtzeroextend(type, buf, n, bsize);
4565e96a66cSDavid du Colombier 	return n;
4575e96a66cSDavid du Colombier }
4585e96a66cSDavid du Colombier 
4595e96a66cSDavid du Colombier static u32int
ventiRoot(char * host,char * s)4605e96a66cSDavid du Colombier ventiRoot(char *host, char *s)
4615e96a66cSDavid du Colombier {
4625e96a66cSDavid du Colombier 	int i, n;
4635e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
4645e96a66cSDavid du Colombier 	u32int addr, tag;
4655e96a66cSDavid du Colombier 	DirEntry de;
4665e96a66cSDavid du Colombier 	MetaBlock mb;
4675e96a66cSDavid du Colombier 	MetaEntry me;
4685e96a66cSDavid du Colombier 	Entry e;
4695e96a66cSDavid du Colombier 	VtRoot root;
4705e96a66cSDavid du Colombier 
4715e96a66cSDavid du Colombier 	if(!parseScore(score, s))
472*d7aba6c3SDavid du Colombier 		sysfatal("bad score '%s'", s);
4735e96a66cSDavid du Colombier 
474*d7aba6c3SDavid du Colombier 	if((z = vtdial(host)) == nil
475*d7aba6c3SDavid du Colombier 	|| vtconnect(z) < 0)
476*d7aba6c3SDavid du Colombier 		sysfatal("connect to venti: %r");
4775e96a66cSDavid du Colombier 
4785e96a66cSDavid du Colombier 	tag = tagGen();
4795e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, tag);
4805e96a66cSDavid du Colombier 
4815e96a66cSDavid du Colombier 	ventiRead(score, VtRootType);
482*d7aba6c3SDavid du Colombier 	if(vtrootunpack(&root, buf) < 0)
483*d7aba6c3SDavid du Colombier 		sysfatal("corrupted root: vtrootunpack");
4845e96a66cSDavid du Colombier 	n = ventiRead(root.score, VtDirType);
4855e96a66cSDavid du Colombier 
4865e96a66cSDavid du Colombier 	/*
4875e96a66cSDavid du Colombier 	 * Fossil's vac archives start with an extra layer of source,
4885e96a66cSDavid du Colombier 	 * but vac's don't.
4895e96a66cSDavid du Colombier 	 */
4905e96a66cSDavid du Colombier 	if(n <= 2*VtEntrySize){
4915e96a66cSDavid du Colombier 		if(!entryUnpack(&e, buf, 0))
492*d7aba6c3SDavid du Colombier 			sysfatal("bad root: top entry");
4935e96a66cSDavid du Colombier 		n = ventiRead(e.score, VtDirType);
4945e96a66cSDavid du Colombier 	}
4955e96a66cSDavid du Colombier 
4965e96a66cSDavid du Colombier 	/*
4975e96a66cSDavid du Colombier 	 * There should be three root sources (and nothing else) here.
4985e96a66cSDavid du Colombier 	 */
4995e96a66cSDavid du Colombier 	for(i=0; i<3; i++){
5005e96a66cSDavid du Colombier 		if(!entryUnpack(&e, buf, i)
5015e96a66cSDavid du Colombier 		|| !(e.flags&VtEntryActive)
5025e96a66cSDavid du Colombier 		|| e.psize < 256
5035e96a66cSDavid du Colombier 		|| e.dsize < 256)
504*d7aba6c3SDavid du Colombier 			sysfatal("bad root: entry %d", i);
5055e96a66cSDavid du Colombier 		fprint(2, "%V\n", e.score);
5065e96a66cSDavid du Colombier 	}
5075e96a66cSDavid du Colombier 	if(n > 3*VtEntrySize)
508*d7aba6c3SDavid du Colombier 		sysfatal("bad root: entry count");
5095e96a66cSDavid du Colombier 
5105e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
5115e96a66cSDavid du Colombier 
5125e96a66cSDavid du Colombier 	/*
5135e96a66cSDavid du Colombier 	 * Maximum qid is recorded in root's msource, entry #2 (conveniently in e).
5145e96a66cSDavid du Colombier 	 */
5155e96a66cSDavid du Colombier 	ventiRead(e.score, VtDataType);
5165e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, buf, bsize))
517*d7aba6c3SDavid du Colombier 		sysfatal("bad root: mbUnpack");
5185e96a66cSDavid du Colombier 	meUnpack(&me, &mb, 0);
5195e96a66cSDavid du Colombier 	if(!deUnpack(&de, &me))
520*d7aba6c3SDavid du Colombier 		sysfatal("bad root: dirUnpack");
5215e96a66cSDavid du Colombier 	if(!de.qidSpace)
522*d7aba6c3SDavid du Colombier 		sysfatal("bad root: no qidSpace");
5235e96a66cSDavid du Colombier 	qid = de.qidMax;
5245e96a66cSDavid du Colombier 
5255e96a66cSDavid du Colombier 	/*
5265e96a66cSDavid du Colombier 	 * Recreate the top layer of source.
5275e96a66cSDavid du Colombier 	 */
5285e96a66cSDavid du Colombier 	entryInit(&e);
529*d7aba6c3SDavid du Colombier 	e.flags |= VtEntryLocal|_VtEntryDir;
5305e96a66cSDavid du Colombier 	e.size = VtEntrySize*3;
5315e96a66cSDavid du Colombier 	e.tag = tag;
5325e96a66cSDavid du Colombier 	localToGlobal(addr, e.score);
5335e96a66cSDavid du Colombier 
5345e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, RootTag);
5355e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
5365e96a66cSDavid du Colombier 	entryPack(&e, buf, 0);
5375e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
5385e96a66cSDavid du Colombier 
5395e96a66cSDavid du Colombier 	return addr;
5405e96a66cSDavid du Colombier }
5415e96a66cSDavid du Colombier 
5425e96a66cSDavid du Colombier static int
parseScore(uchar * score,char * buf)5435e96a66cSDavid du Colombier parseScore(uchar *score, char *buf)
5445e96a66cSDavid du Colombier {
5455e96a66cSDavid du Colombier 	int i, c;
5465e96a66cSDavid du Colombier 
5475e96a66cSDavid du Colombier 	memset(score, 0, VtScoreSize);
5485e96a66cSDavid du Colombier 
5495e96a66cSDavid du Colombier 	if(strlen(buf) < VtScoreSize*2)
5505e96a66cSDavid du Colombier 		return 0;
5515e96a66cSDavid du Colombier 	for(i=0; i<VtScoreSize*2; i++){
5525e96a66cSDavid du Colombier 		if(buf[i] >= '0' && buf[i] <= '9')
5535e96a66cSDavid du Colombier 			c = buf[i] - '0';
5545e96a66cSDavid du Colombier 		else if(buf[i] >= 'a' && buf[i] <= 'f')
5555e96a66cSDavid du Colombier 			c = buf[i] - 'a' + 10;
5565e96a66cSDavid du Colombier 		else if(buf[i] >= 'A' && buf[i] <= 'F')
5575e96a66cSDavid du Colombier 			c = buf[i] - 'A' + 10;
5585e96a66cSDavid du Colombier 		else
5595e96a66cSDavid du Colombier 			return 0;
5605e96a66cSDavid du Colombier 
5615e96a66cSDavid du Colombier 		if((i & 1) == 0)
5625e96a66cSDavid du Colombier 			c <<= 4;
5635e96a66cSDavid du Colombier 
5645e96a66cSDavid du Colombier 		score[i>>1] |= c;
5655e96a66cSDavid du Colombier 	}
5665e96a66cSDavid du Colombier 	return 1;
5675e96a66cSDavid du Colombier }
568