xref: /plan9/sys/src/cmd/fossil/flfmt.c (revision 2651f6bb1dce6979361f5f2d230af377da2d5a92)
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*);
215e96a66cSDavid du Colombier static VtSession *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
main(int argc,char * argv[])495e96a66cSDavid du Colombier main(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)
99fe853e23SDavid du Colombier 		vtFatal("cannot use -i with -v");
100fe853e23SDavid du Colombier 
1015e96a66cSDavid du Colombier 	vtAttach();
1025e96a66cSDavid du Colombier 
1035e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
1045e96a66cSDavid du Colombier 	fmtinstall('R', vtErrFmt);
1055e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
1065e96a66cSDavid du Colombier 
1075e96a66cSDavid du Colombier 	fd = open(argv[0], ORDWR);
1085e96a66cSDavid du Colombier 	if(fd < 0)
1095e96a66cSDavid du Colombier 		vtFatal("could not open file: %s: %r", argv[0]);
1105e96a66cSDavid du Colombier 
1115e96a66cSDavid du Colombier 	buf = vtMemAllocZ(bsize);
1125e96a66cSDavid du Colombier 	if(pread(fd, buf, bsize, HeaderOffset) != bsize)
1135e96a66cSDavid du Colombier 		vtFatal("could not read fs header block: %r");
1145e96a66cSDavid du Colombier 
1155e96a66cSDavid du Colombier 	if(headerUnpack(&h, buf) && !force
1165e96a66cSDavid du Colombier 	&& !confirm("fs header block already exists; are you sure?"))
1175e96a66cSDavid du Colombier 		goto Out;
1185e96a66cSDavid du Colombier 
1195e96a66cSDavid du Colombier 	if((d = dirfstat(fd)) == nil)
1205e96a66cSDavid du Colombier 		vtFatal("dirfstat: %r");
1215e96a66cSDavid du Colombier 
1225e96a66cSDavid du Colombier 	if(d->type == 'M' && !force
1235e96a66cSDavid du Colombier 	&& !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?"))
1245e96a66cSDavid du Colombier 		goto Out;
1255e96a66cSDavid du Colombier 
1265e96a66cSDavid du Colombier 	partition(fd, bsize, &h);
1275e96a66cSDavid du Colombier 	headerPack(&h, buf);
1285e96a66cSDavid du Colombier 	if(pwrite(fd, buf, bsize, HeaderOffset) < bsize)
1295e96a66cSDavid du Colombier 		vtFatal("could not write fs header: %r");
1305e96a66cSDavid du Colombier 
1315e96a66cSDavid du Colombier 	disk = diskAlloc(fd);
1325e96a66cSDavid du Colombier 	if(disk == nil)
1335e96a66cSDavid du Colombier 		vtFatal("could not open disk: %r");
1345e96a66cSDavid du Colombier 
135fe853e23SDavid du Colombier 	if(iso9660file)
136fe853e23SDavid du Colombier 		iso9660init(fd, &h, iso9660file, iso9660off);
137fe853e23SDavid du Colombier 
1385e96a66cSDavid du Colombier 	/* zero labels */
1395e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
1405e96a66cSDavid du Colombier 	for(bn = 0; bn < diskSize(disk, PartLabel); bn++)
1415e96a66cSDavid du Colombier 		blockWrite(PartLabel, bn);
1425e96a66cSDavid du Colombier 
143fe853e23SDavid du Colombier 	if(iso9660file)
144fe853e23SDavid du Colombier 		iso9660labels(disk, buf, blockWrite);
145fe853e23SDavid du Colombier 
1465e96a66cSDavid du Colombier 	if(score)
1475e96a66cSDavid du Colombier 		root = ventiRoot(host, score);
1485e96a66cSDavid du Colombier 	else{
1495e96a66cSDavid du Colombier 		rootMetaInit(&e);
1505e96a66cSDavid du Colombier 		root = rootInit(&e);
1515e96a66cSDavid du Colombier 	}
1525e96a66cSDavid du Colombier 
1537abd426fSDavid du Colombier 	superInit(label, root, vtZeroScore);
1545e96a66cSDavid du Colombier 	diskFree(disk);
1555e96a66cSDavid du Colombier 
156e6c6b7f8SDavid du Colombier 	if(score == nil)
1575e96a66cSDavid du Colombier 		topLevel(argv[0]);
1585e96a66cSDavid du Colombier 
1595e96a66cSDavid du Colombier Out:
1605e96a66cSDavid du Colombier 	vtDetach();
1615e96a66cSDavid du Colombier 	exits(0);
1625e96a66cSDavid du Colombier }
1635e96a66cSDavid du Colombier 
1645e96a66cSDavid du Colombier static u64int
fdsize(int fd)1655e96a66cSDavid du Colombier fdsize(int fd)
1665e96a66cSDavid du Colombier {
1675e96a66cSDavid du Colombier 	Dir *dir;
1685e96a66cSDavid du Colombier 	u64int size;
1695e96a66cSDavid du Colombier 
1705e96a66cSDavid du Colombier 	dir = dirfstat(fd);
1715e96a66cSDavid du Colombier 	if(dir == nil)
1725e96a66cSDavid du Colombier 		vtFatal("could not stat file: %r");
1735e96a66cSDavid du Colombier 	size = dir->length;
1745e96a66cSDavid du Colombier 	free(dir);
1755e96a66cSDavid du Colombier 	return size;
1765e96a66cSDavid du Colombier }
1775e96a66cSDavid du Colombier 
1785e96a66cSDavid du Colombier static void
usage(void)1795e96a66cSDavid du Colombier usage(void)
1805e96a66cSDavid du Colombier {
181*0c6300e7SDavid du Colombier 	fprint(2, "usage: %s [-b blocksize] [-h host] [-i file offset] "
182*0c6300e7SDavid du Colombier 		"[-l label] [-v score] [-y] file\n", argv0);
1835e96a66cSDavid du Colombier 	exits("usage");
1845e96a66cSDavid du Colombier }
1855e96a66cSDavid du Colombier 
1865e96a66cSDavid du Colombier static void
partition(int fd,int bsize,Header * h)1875e96a66cSDavid du Colombier partition(int fd, int bsize, Header *h)
1885e96a66cSDavid du Colombier {
1895e96a66cSDavid du Colombier 	ulong nblock, ndata, nlabel;
1905e96a66cSDavid du Colombier 	ulong lpb;
1915e96a66cSDavid du Colombier 
1925e96a66cSDavid du Colombier 	if(bsize % 512 != 0)
1935e96a66cSDavid du Colombier 		sysfatal("block size must be a multiple of 512 bytes");
1945e96a66cSDavid du Colombier 	if(bsize > VtMaxLumpSize)
1955e96a66cSDavid du Colombier 		sysfatal("block size must be less than %d", VtMaxLumpSize);
1965e96a66cSDavid du Colombier 
1975e96a66cSDavid du Colombier 	memset(h, 0, sizeof(*h));
1985e96a66cSDavid du Colombier 	h->blockSize = bsize;
1995e96a66cSDavid du Colombier 
2005e96a66cSDavid du Colombier 	lpb = bsize/LabelSize;
2015e96a66cSDavid du Colombier 
2025e96a66cSDavid du Colombier 	nblock = fdsize(fd)/bsize;
2035e96a66cSDavid du Colombier 
2045e96a66cSDavid du Colombier 	/* sanity check */
2055e96a66cSDavid du Colombier 	if(nblock < (HeaderOffset*10)/bsize)
2065e96a66cSDavid du Colombier 		vtFatal("file too small");
2075e96a66cSDavid du Colombier 
2085e96a66cSDavid du Colombier 	h->super = (HeaderOffset + 2*bsize)/bsize;
2095e96a66cSDavid du Colombier 	h->label = h->super + 1;
2105e96a66cSDavid du Colombier 	ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1);
2115e96a66cSDavid du Colombier 	nlabel = (ndata + lpb - 1)/lpb;
2125e96a66cSDavid du Colombier 	h->data = h->label + nlabel;
2135e96a66cSDavid du Colombier 	h->end = h->data + ndata;
2145e96a66cSDavid du Colombier 
2155e96a66cSDavid du Colombier }
2165e96a66cSDavid du Colombier 
2175e96a66cSDavid du Colombier static u32int
tagGen(void)2185e96a66cSDavid du Colombier tagGen(void)
2195e96a66cSDavid du Colombier {
2205e96a66cSDavid du Colombier 	u32int tag;
2215e96a66cSDavid du Colombier 
2225e96a66cSDavid du Colombier 	for(;;){
2235e96a66cSDavid du Colombier 		tag = lrand();
2245e96a66cSDavid du Colombier 		if(tag > RootTag)
2255e96a66cSDavid du Colombier 			break;
2265e96a66cSDavid du Colombier 	}
2275e96a66cSDavid du Colombier 	return tag;
2285e96a66cSDavid du Colombier }
2295e96a66cSDavid du Colombier 
2305e96a66cSDavid du Colombier static void
entryInit(Entry * e)2315e96a66cSDavid du Colombier entryInit(Entry *e)
2325e96a66cSDavid du Colombier {
2335e96a66cSDavid du Colombier 	e->gen = 0;
2345e96a66cSDavid du Colombier 	e->dsize = bsize;
2355e96a66cSDavid du Colombier 	e->psize = bsize/VtEntrySize*VtEntrySize;
2365e96a66cSDavid du Colombier 	e->flags = VtEntryActive;
2375e96a66cSDavid du Colombier 	e->depth = 0;
2385e96a66cSDavid du Colombier 	e->size = 0;
2395e96a66cSDavid du Colombier 	memmove(e->score, vtZeroScore, VtScoreSize);
2405e96a66cSDavid du Colombier 	e->tag = tagGen();
2415e96a66cSDavid du Colombier 	e->snap = 0;
2425e96a66cSDavid du Colombier 	e->archive = 0;
2435e96a66cSDavid du Colombier }
2445e96a66cSDavid du Colombier 
2455e96a66cSDavid du Colombier static void
rootMetaInit(Entry * e)2465e96a66cSDavid du Colombier rootMetaInit(Entry *e)
2475e96a66cSDavid du Colombier {
2485e96a66cSDavid du Colombier 	u32int addr;
2495e96a66cSDavid du Colombier 	u32int tag;
2505e96a66cSDavid du Colombier 	DirEntry de;
2515e96a66cSDavid du Colombier 	MetaBlock mb;
2525e96a66cSDavid du Colombier 	MetaEntry me;
2535e96a66cSDavid du Colombier 
2545e96a66cSDavid du Colombier 	memset(&de, 0, sizeof(de));
2555e96a66cSDavid du Colombier 	de.elem = vtStrDup("root");
2565e96a66cSDavid du Colombier 	de.entry = 0;
2575e96a66cSDavid du Colombier 	de.gen = 0;
2585e96a66cSDavid du Colombier 	de.mentry = 1;
2595e96a66cSDavid du Colombier 	de.mgen = 0;
2605e96a66cSDavid du Colombier 	de.size = 0;
2615e96a66cSDavid du Colombier 	de.qid = qid++;
2625e96a66cSDavid du Colombier 	de.uid = vtStrDup("adm");
2635e96a66cSDavid du Colombier 	de.gid = vtStrDup("adm");
2645e96a66cSDavid du Colombier 	de.mid = vtStrDup("adm");
2655e96a66cSDavid du Colombier 	de.mtime = time(0);
2665e96a66cSDavid du Colombier 	de.mcount = 0;
2675e96a66cSDavid du Colombier 	de.ctime = time(0);
2685e96a66cSDavid du Colombier 	de.atime = time(0);
2695e96a66cSDavid du Colombier 	de.mode = ModeDir | 0555;
2705e96a66cSDavid du Colombier 
2715e96a66cSDavid du Colombier 	tag = tagGen();
2725e96a66cSDavid du Colombier 	addr = blockAlloc(BtData, tag);
2735e96a66cSDavid du Colombier 
2745e96a66cSDavid du Colombier 	/* build up meta block */
2755e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
2765e96a66cSDavid du Colombier 	mbInit(&mb, buf, bsize, bsize/100);
2775e96a66cSDavid du Colombier 	me.size = deSize(&de);
2785e96a66cSDavid du Colombier 	me.p = mbAlloc(&mb, me.size);
2795e96a66cSDavid du Colombier 	assert(me.p != nil);
2805e96a66cSDavid du Colombier 	dePack(&de, &me);
2815e96a66cSDavid du Colombier 	mbInsert(&mb, 0, &me);
2825e96a66cSDavid du Colombier 	mbPack(&mb);
2835e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
2845e96a66cSDavid du Colombier 	deCleanup(&de);
2855e96a66cSDavid du Colombier 
2865e96a66cSDavid du Colombier 	/* build up entry for meta block */
2875e96a66cSDavid du Colombier 	entryInit(e);
2885e96a66cSDavid du Colombier 	e->flags |= VtEntryLocal;
2895e96a66cSDavid du Colombier  	e->size = bsize;
2905e96a66cSDavid du Colombier 	e->tag = tag;
2915e96a66cSDavid du Colombier 	localToGlobal(addr, e->score);
2925e96a66cSDavid du Colombier }
2935e96a66cSDavid du Colombier 
2945e96a66cSDavid du Colombier static u32int
rootInit(Entry * e)2955e96a66cSDavid du Colombier rootInit(Entry *e)
2965e96a66cSDavid du Colombier {
2975e96a66cSDavid du Colombier 	ulong addr;
2985e96a66cSDavid du Colombier 	u32int tag;
2995e96a66cSDavid du Colombier 
3005e96a66cSDavid du Colombier 	tag = tagGen();
3015e96a66cSDavid du Colombier 
3025e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, tag);
3035e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3045e96a66cSDavid du Colombier 
3055e96a66cSDavid du Colombier 	/* root meta data is in the third entry */
3065e96a66cSDavid du Colombier 	entryPack(e, buf, 2);
3075e96a66cSDavid du Colombier 
3085e96a66cSDavid du Colombier 	entryInit(e);
3095e96a66cSDavid du Colombier 	e->flags |= VtEntryDir;
3105e96a66cSDavid du Colombier 	entryPack(e, buf, 0);
3115e96a66cSDavid du Colombier 
3125e96a66cSDavid du Colombier 	entryInit(e);
3135e96a66cSDavid du Colombier 	entryPack(e, buf, 1);
3145e96a66cSDavid du Colombier 
3155e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
3165e96a66cSDavid du Colombier 
3175e96a66cSDavid du Colombier 	entryInit(e);
3185e96a66cSDavid du Colombier 	e->flags |= VtEntryLocal|VtEntryDir;
3195e96a66cSDavid du Colombier  	e->size = VtEntrySize*3;
3205e96a66cSDavid du Colombier 	e->tag = tag;
3215e96a66cSDavid du Colombier 	localToGlobal(addr, e->score);
3225e96a66cSDavid du Colombier 
3235e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, RootTag);
3245e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3255e96a66cSDavid du Colombier 	entryPack(e, buf, 0);
3265e96a66cSDavid du Colombier 
3275e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
3285e96a66cSDavid du Colombier 
3295e96a66cSDavid du Colombier 	return addr;
3305e96a66cSDavid du Colombier }
3315e96a66cSDavid du Colombier 
3325e96a66cSDavid du Colombier 
3335e96a66cSDavid du Colombier static u32int
blockAlloc(int type,u32int tag)3345e96a66cSDavid du Colombier blockAlloc(int type, u32int tag)
3355e96a66cSDavid du Colombier {
3365e96a66cSDavid du Colombier 	static u32int addr;
3375e96a66cSDavid du Colombier 	Label l;
3385e96a66cSDavid du Colombier 	int lpb;
3395e96a66cSDavid du Colombier 
3405e96a66cSDavid du Colombier 	lpb = bsize/LabelSize;
3415e96a66cSDavid du Colombier 
3425e96a66cSDavid du Colombier 	blockRead(PartLabel, addr/lpb);
343fe853e23SDavid du Colombier 	if(!labelUnpack(&l, buf, addr % lpb))
3445e96a66cSDavid du Colombier 		vtFatal("bad label: %r");
345fe853e23SDavid du Colombier 	if(l.state != BsFree)
346fe853e23SDavid du Colombier 		vtFatal("want to allocate block already in use");
3475e96a66cSDavid du Colombier 	l.epoch = 1;
3485e96a66cSDavid du Colombier 	l.epochClose = ~(u32int)0;
3495e96a66cSDavid du Colombier 	l.type = type;
3505e96a66cSDavid du Colombier 	l.state = BsAlloc;
3515e96a66cSDavid du Colombier 	l.tag = tag;
3525e96a66cSDavid du Colombier 	labelPack(&l, buf, addr % lpb);
3535e96a66cSDavid du Colombier 	blockWrite(PartLabel, addr/lpb);
3545e96a66cSDavid du Colombier 	return addr++;
3555e96a66cSDavid du Colombier }
3565e96a66cSDavid du Colombier 
3575e96a66cSDavid du Colombier static void
superInit(char * label,u32int root,uchar score[VtScoreSize])3587abd426fSDavid du Colombier superInit(char *label, u32int root, uchar score[VtScoreSize])
3595e96a66cSDavid du Colombier {
3605e96a66cSDavid du Colombier 	Super s;
3615e96a66cSDavid du Colombier 
3625e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
3635e96a66cSDavid du Colombier 	memset(&s, 0, sizeof(s));
3645e96a66cSDavid du Colombier 	s.version = SuperVersion;
3655e96a66cSDavid du Colombier 	s.epochLow = 1;
3665e96a66cSDavid du Colombier 	s.epochHigh = 1;
3675e96a66cSDavid du Colombier 	s.qid = qid;
3685e96a66cSDavid du Colombier 	s.active = root;
3695e96a66cSDavid du Colombier 	s.next = NilBlock;
3705e96a66cSDavid du Colombier 	s.current = NilBlock;
3715e96a66cSDavid du Colombier 	strecpy(s.name, s.name+sizeof(s.name), label);
3727abd426fSDavid du Colombier 	memmove(s.last, score, VtScoreSize);
3735e96a66cSDavid du Colombier 
3745e96a66cSDavid du Colombier 	superPack(&s, buf);
3755e96a66cSDavid du Colombier 	blockWrite(PartSuper, 0);
3765e96a66cSDavid du Colombier }
3775e96a66cSDavid du Colombier 
3785e96a66cSDavid du Colombier static u64int
unittoull(char * s)3795e96a66cSDavid du Colombier unittoull(char *s)
3805e96a66cSDavid du Colombier {
3815e96a66cSDavid du Colombier 	char *es;
3825e96a66cSDavid du Colombier 	u64int n;
3835e96a66cSDavid du Colombier 
3845e96a66cSDavid du Colombier 	if(s == nil)
3855e96a66cSDavid du Colombier 		return TWID64;
3865e96a66cSDavid du Colombier 	n = strtoul(s, &es, 0);
3875e96a66cSDavid du Colombier 	if(*es == 'k' || *es == 'K'){
3885e96a66cSDavid du Colombier 		n *= 1024;
3895e96a66cSDavid du Colombier 		es++;
3905e96a66cSDavid du Colombier 	}else if(*es == 'm' || *es == 'M'){
3915e96a66cSDavid du Colombier 		n *= 1024*1024;
3925e96a66cSDavid du Colombier 		es++;
3935e96a66cSDavid du Colombier 	}else if(*es == 'g' || *es == 'G'){
3945e96a66cSDavid du Colombier 		n *= 1024*1024*1024;
3955e96a66cSDavid du Colombier 		es++;
3965e96a66cSDavid du Colombier 	}
3975e96a66cSDavid du Colombier 	if(*es != '\0')
3985e96a66cSDavid du Colombier 		return TWID64;
3995e96a66cSDavid du Colombier 	return n;
4005e96a66cSDavid du Colombier }
4015e96a66cSDavid du Colombier 
4025e96a66cSDavid du Colombier static void
blockRead(int part,u32int addr)4035e96a66cSDavid du Colombier blockRead(int part, u32int addr)
4045e96a66cSDavid du Colombier {
4055e96a66cSDavid du Colombier 	if(!diskReadRaw(disk, part, addr, buf))
4065e96a66cSDavid du Colombier 		vtFatal("read failed: %r");
4075e96a66cSDavid du Colombier }
4085e96a66cSDavid du Colombier 
4095e96a66cSDavid du Colombier static void
blockWrite(int part,u32int addr)4105e96a66cSDavid du Colombier blockWrite(int part, u32int addr)
4115e96a66cSDavid du Colombier {
4125e96a66cSDavid du Colombier 	if(!diskWriteRaw(disk, part, addr, buf))
4135e96a66cSDavid du Colombier 		vtFatal("write failed: %r");
4145e96a66cSDavid du Colombier }
4155e96a66cSDavid du Colombier 
4165e96a66cSDavid du Colombier static void
addFile(File * root,char * name,uint mode)4175e96a66cSDavid du Colombier addFile(File *root, char *name, uint mode)
4185e96a66cSDavid du Colombier {
4195e96a66cSDavid du Colombier 	File *f;
4205e96a66cSDavid du Colombier 
4215e96a66cSDavid du Colombier 	f = fileCreate(root, name, mode | ModeDir, "adm");
4225e96a66cSDavid du Colombier 	if(f == nil)
4235e96a66cSDavid du Colombier 		vtFatal("could not create file: %s: %r", name);
4245e96a66cSDavid du Colombier 	fileDecRef(f);
4255e96a66cSDavid du Colombier }
4265e96a66cSDavid du Colombier 
4275e96a66cSDavid du Colombier static void
topLevel(char * name)4285e96a66cSDavid du Colombier topLevel(char *name)
4295e96a66cSDavid du Colombier {
4305e96a66cSDavid du Colombier 	Fs *fs;
4315e96a66cSDavid du Colombier 	File *root;
4325e96a66cSDavid du Colombier 
4335e96a66cSDavid du Colombier 	/* ok, now we can open as a fs */
4345e96a66cSDavid du Colombier 	fs = fsOpen(name, z, 100, OReadWrite);
4355e96a66cSDavid du Colombier 	if(fs == nil)
4365e96a66cSDavid du Colombier 		vtFatal("could not open file system: %r");
4375e96a66cSDavid du Colombier 	vtRLock(fs->elk);
4385e96a66cSDavid du Colombier 	root = fsGetRoot(fs);
4395e96a66cSDavid du Colombier 	if(root == nil)
4405e96a66cSDavid du Colombier 		vtFatal("could not open root: %r");
441c3c4501eSDavid du Colombier 	addFile(root, "active", 0555);
4425e96a66cSDavid du Colombier 	addFile(root, "archive", 0555);
4435e96a66cSDavid du Colombier 	addFile(root, "snapshot", 0555);
4445e96a66cSDavid du Colombier 	fileDecRef(root);
445fe853e23SDavid du Colombier 	if(iso9660file)
446fe853e23SDavid du Colombier 		iso9660copy(fs);
4475e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
4485e96a66cSDavid du Colombier 	fsClose(fs);
4495e96a66cSDavid du Colombier }
4505e96a66cSDavid du Colombier 
4515e96a66cSDavid du Colombier static int
ventiRead(uchar score[VtScoreSize],int type)4525e96a66cSDavid du Colombier ventiRead(uchar score[VtScoreSize], int type)
4535e96a66cSDavid du Colombier {
4545e96a66cSDavid du Colombier 	int n;
4555e96a66cSDavid du Colombier 
4565e96a66cSDavid du Colombier 	n = vtRead(z, score, type, buf, bsize);
4575e96a66cSDavid du Colombier 	if(n < 0)
4585e96a66cSDavid du Colombier 		vtFatal("ventiRead %V (%d) failed: %R", score, type);
4595e96a66cSDavid du Colombier 	vtZeroExtend(type, buf, n, bsize);
4605e96a66cSDavid du Colombier 	return n;
4615e96a66cSDavid du Colombier }
4625e96a66cSDavid du Colombier 
4635e96a66cSDavid du Colombier static u32int
ventiRoot(char * host,char * s)4645e96a66cSDavid du Colombier ventiRoot(char *host, char *s)
4655e96a66cSDavid du Colombier {
4665e96a66cSDavid du Colombier 	int i, n;
4675e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
4685e96a66cSDavid du Colombier 	u32int addr, tag;
4695e96a66cSDavid du Colombier 	DirEntry de;
4705e96a66cSDavid du Colombier 	MetaBlock mb;
4715e96a66cSDavid du Colombier 	MetaEntry me;
4725e96a66cSDavid du Colombier 	Entry e;
4735e96a66cSDavid du Colombier 	VtRoot root;
4745e96a66cSDavid du Colombier 
4755e96a66cSDavid du Colombier 	if(!parseScore(score, s))
4765e96a66cSDavid du Colombier 		vtFatal("bad score '%s'", s);
4775e96a66cSDavid du Colombier 
4785e96a66cSDavid du Colombier 	if((z = vtDial(host, 0)) == nil
4795e96a66cSDavid du Colombier 	|| !vtConnect(z, nil))
4805e96a66cSDavid du Colombier 		vtFatal("connect to venti: %R");
4815e96a66cSDavid du Colombier 
4825e96a66cSDavid du Colombier 	tag = tagGen();
4835e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, tag);
4845e96a66cSDavid du Colombier 
4855e96a66cSDavid du Colombier 	ventiRead(score, VtRootType);
4865e96a66cSDavid du Colombier 	if(!vtRootUnpack(&root, buf))
4875e96a66cSDavid du Colombier 		vtFatal("corrupted root: vtRootUnpack");
4885e96a66cSDavid du Colombier 	n = ventiRead(root.score, VtDirType);
4895e96a66cSDavid du Colombier 
4905e96a66cSDavid du Colombier 	/*
4915e96a66cSDavid du Colombier 	 * Fossil's vac archives start with an extra layer of source,
4925e96a66cSDavid du Colombier 	 * but vac's don't.
4935e96a66cSDavid du Colombier 	 */
4945e96a66cSDavid du Colombier 	if(n <= 2*VtEntrySize){
4955e96a66cSDavid du Colombier 		if(!entryUnpack(&e, buf, 0))
4965e96a66cSDavid du Colombier 			vtFatal("bad root: top entry");
4975e96a66cSDavid du Colombier 		n = ventiRead(e.score, VtDirType);
4985e96a66cSDavid du Colombier 	}
4995e96a66cSDavid du Colombier 
5005e96a66cSDavid du Colombier 	/*
5015e96a66cSDavid du Colombier 	 * There should be three root sources (and nothing else) here.
5025e96a66cSDavid du Colombier 	 */
5035e96a66cSDavid du Colombier 	for(i=0; i<3; i++){
5045e96a66cSDavid du Colombier 		if(!entryUnpack(&e, buf, i)
5055e96a66cSDavid du Colombier 		|| !(e.flags&VtEntryActive)
5065e96a66cSDavid du Colombier 		|| e.psize < 256
5075e96a66cSDavid du Colombier 		|| e.dsize < 256)
5085e96a66cSDavid du Colombier 			vtFatal("bad root: entry %d", i);
5095e96a66cSDavid du Colombier 		fprint(2, "%V\n", e.score);
5105e96a66cSDavid du Colombier 	}
5115e96a66cSDavid du Colombier 	if(n > 3*VtEntrySize)
5125e96a66cSDavid du Colombier 		vtFatal("bad root: entry count");
5135e96a66cSDavid du Colombier 
5145e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
5155e96a66cSDavid du Colombier 
5165e96a66cSDavid du Colombier 	/*
5175e96a66cSDavid du Colombier 	 * Maximum qid is recorded in root's msource, entry #2 (conveniently in e).
5185e96a66cSDavid du Colombier 	 */
5195e96a66cSDavid du Colombier 	ventiRead(e.score, VtDataType);
5205e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, buf, bsize))
5215e96a66cSDavid du Colombier 		vtFatal("bad root: mbUnpack");
5225e96a66cSDavid du Colombier 	meUnpack(&me, &mb, 0);
5235e96a66cSDavid du Colombier 	if(!deUnpack(&de, &me))
5245e96a66cSDavid du Colombier 		vtFatal("bad root: dirUnpack");
5255e96a66cSDavid du Colombier 	if(!de.qidSpace)
5265e96a66cSDavid du Colombier 		vtFatal("bad root: no qidSpace");
5275e96a66cSDavid du Colombier 	qid = de.qidMax;
5285e96a66cSDavid du Colombier 
5295e96a66cSDavid du Colombier 	/*
5305e96a66cSDavid du Colombier 	 * Recreate the top layer of source.
5315e96a66cSDavid du Colombier 	 */
5325e96a66cSDavid du Colombier 	entryInit(&e);
5335e96a66cSDavid du Colombier 	e.flags |= VtEntryLocal|VtEntryDir;
5345e96a66cSDavid du Colombier 	e.size = VtEntrySize*3;
5355e96a66cSDavid du Colombier 	e.tag = tag;
5365e96a66cSDavid du Colombier 	localToGlobal(addr, e.score);
5375e96a66cSDavid du Colombier 
5385e96a66cSDavid du Colombier 	addr = blockAlloc(BtDir, RootTag);
5395e96a66cSDavid du Colombier 	memset(buf, 0, bsize);
5405e96a66cSDavid du Colombier 	entryPack(&e, buf, 0);
5415e96a66cSDavid du Colombier 	blockWrite(PartData, addr);
5425e96a66cSDavid du Colombier 
5435e96a66cSDavid du Colombier 	return addr;
5445e96a66cSDavid du Colombier }
5455e96a66cSDavid du Colombier 
5465e96a66cSDavid du Colombier static int
parseScore(uchar * score,char * buf)5475e96a66cSDavid du Colombier parseScore(uchar *score, char *buf)
5485e96a66cSDavid du Colombier {
5495e96a66cSDavid du Colombier 	int i, c;
5505e96a66cSDavid du Colombier 
5515e96a66cSDavid du Colombier 	memset(score, 0, VtScoreSize);
5525e96a66cSDavid du Colombier 
5535e96a66cSDavid du Colombier 	if(strlen(buf) < VtScoreSize*2)
5545e96a66cSDavid du Colombier 		return 0;
5555e96a66cSDavid du Colombier 	for(i=0; i<VtScoreSize*2; i++){
5565e96a66cSDavid du Colombier 		if(buf[i] >= '0' && buf[i] <= '9')
5575e96a66cSDavid du Colombier 			c = buf[i] - '0';
5585e96a66cSDavid du Colombier 		else if(buf[i] >= 'a' && buf[i] <= 'f')
5595e96a66cSDavid du Colombier 			c = buf[i] - 'a' + 10;
5605e96a66cSDavid du Colombier 		else if(buf[i] >= 'A' && buf[i] <= 'F')
5615e96a66cSDavid du Colombier 			c = buf[i] - 'A' + 10;
5625e96a66cSDavid du Colombier 		else
5635e96a66cSDavid du Colombier 			return 0;
5645e96a66cSDavid du Colombier 
5655e96a66cSDavid du Colombier 		if((i & 1) == 0)
5665e96a66cSDavid du Colombier 			c <<= 4;
5675e96a66cSDavid du Colombier 
5685e96a66cSDavid du Colombier 		score[i>>1] |= c;
5695e96a66cSDavid du Colombier 	}
5705e96a66cSDavid du Colombier 	return 1;
5715e96a66cSDavid du Colombier }
572