580 lines · 10.8 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "stdinc.h"#include "dat.h"#include "fns.h"#include "flfmt9660.h" #define blockWrite _blockWrite	/* hack */ static void usage(void);static u64int fdsize(int fd);static void partition(int fd, int bsize, Header *h);static u64int unittoull(char *s);static u32int blockAlloc(int type, u32int tag);static void blockRead(int part, u32int addr);static void blockWrite(int part, u32int addr);static void superInit(char *label, u32int root, uchar[VtScoreSize]);static void rootMetaInit(Entry *e);static u32int rootInit(Entry *e);static void topLevel(char *name);static int parseScore(uchar[VtScoreSize], char*);static u32int ventiRoot(char*, char*);static VtSession *z; #define TWID64	((u64int)~(u64int)0) Disk *disk;Fs *fs;uchar *buf;int bsize = 8*1024;u64int qid = 1;int iso9660off;char *iso9660file; intconfirm(char *msg){	char buf[100];	int n; 	fprint(2, "%s [y/n]: ", msg);	n = read(0, buf, sizeof buf - 1);	if(n <= 0)		return 0;	if(buf[0] == 'y')		return 1;	return 0;} voidmain(int argc, char *argv[]){	int fd, force;	Header h;	ulong bn;	Entry e;	char *label = "vfs";	char *host = nil;	char *score = nil;	u32int root;	Dir *d; 	force = 0;	ARGBEGIN{	default:		usage();	case 'b':		bsize = unittoull(EARGF(usage()));		if(bsize == ~0)			usage();		break;	case 'h':		host = EARGF(usage());		break;	case 'i':		iso9660file = EARGF(usage());		iso9660off = atoi(EARGF(usage()));		break;	case 'l':		label = EARGF(usage());		break;	case 'v':		score = EARGF(usage());		break; 	/*	 * This is -y instead of -f because flchk has a	 * (frequently used) -f option.  I type flfmt instead	 * of flchk all the time, and want to make it hard	 * to reformat my file system accidentally.	 */	case 'y':		force = 1;		break;	}ARGEND 	if(argc != 1)		usage(); 	if(iso9660file && score)		vtFatal("cannot use -i with -v"); 	vtAttach(); 	fmtinstall('V', scoreFmt);	fmtinstall('R', vtErrFmt);	fmtinstall('L', labelFmt); 	fd = open(argv[0], ORDWR);	if(fd < 0)		vtFatal("could not open file: %s: %r", argv[0]); 	buf = vtMemAllocZ(bsize);	if(pread(fd, buf, bsize, HeaderOffset) != bsize)		vtFatal("could not read fs header block: %r"); 	if(headerUnpack(&h, buf) && !force	&& !confirm("fs header block already exists; are you sure?"))		goto Out; 	if((d = dirfstat(fd)) == nil)		vtFatal("dirfstat: %r"); 	if(d->type == 'M' && !force	&& !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?"))		goto Out; 	partition(fd, bsize, &h);	headerPack(&h, buf);	if(pwrite(fd, buf, bsize, HeaderOffset) < bsize)		vtFatal("could not write fs header: %r"); 	disk = diskAlloc(fd);	if(disk == nil)		vtFatal("could not open disk: %r"); 	if(iso9660file)		iso9660init(fd, &h, iso9660file, iso9660off); 	/* zero labels */	memset(buf, 0, bsize);	for(bn = 0; bn < diskSize(disk, PartLabel); bn++)		blockWrite(PartLabel, bn); 	if(iso9660file)		iso9660labels(disk, buf, blockWrite); 	if(score)		root = ventiRoot(host, score);	else{		rootMetaInit(&e);		root = rootInit(&e);	} 	superInit(label, root, vtZeroScore);	diskFree(disk); 	if(score == nil)		topLevel(argv[0]); Out:	vtDetach();	exits(0);} static u64intfdsize(int fd){	Dir *dir;	u64int size; 	dir = dirfstat(fd);	if(dir == nil)		vtFatal("could not stat file: %r");	size = dir->length;	free(dir);	return size;} static voidusage(void){	fprint(2, "usage: %s [-b blocksize] [-h host] [-i file offset] "		"[-l label] [-v score] [-y] file\n", argv0);	exits("usage");} static voidpartition(int fd, int bsize, Header *h){	ulong nblock, ndata, nlabel;	ulong lpb; 	if(bsize % 512 != 0)		sysfatal("block size must be a multiple of 512 bytes");	if(bsize > VtMaxLumpSize)		sysfatal("block size must be less than %d", VtMaxLumpSize); 	memset(h, 0, sizeof(*h));	h->blockSize = bsize; 	lpb = bsize/LabelSize; 	nblock = fdsize(fd)/bsize; 	/* sanity check */	if(nblock < (HeaderOffset*10)/bsize)		vtFatal("file too small"); 	h->super = (HeaderOffset + 2*bsize)/bsize;	h->label = h->super + 1;	ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1);	nlabel = (ndata + lpb - 1)/lpb;	h->data = h->label + nlabel;	h->end = h->data + ndata; } static u32inttagGen(void){	u32int tag; 	for(;;){		tag = lrand();		if(tag > RootTag)			break;	}	return tag;} static voidentryInit(Entry *e){	e->gen = 0;	e->dsize = bsize;	e->psize = bsize/VtEntrySize*VtEntrySize;	e->flags = VtEntryActive;	e->depth = 0;	e->size = 0;	memmove(e->score, vtZeroScore, VtScoreSize);	e->tag = tagGen();	e->snap = 0;	e->archive = 0;} static voidrootMetaInit(Entry *e){	u32int addr;	u32int tag;	DirEntry de;	MetaBlock mb;	MetaEntry me; 	memset(&de, 0, sizeof(de));	de.elem = vtStrDup("root");	de.entry = 0;	de.gen = 0;	de.mentry = 1;	de.mgen = 0;	de.size = 0;	de.qid = qid++;	de.uid = vtStrDup("adm");	de.gid = vtStrDup("adm");	de.mid = vtStrDup("adm");	de.mtime = time(0);	de.mcount = 0;	de.ctime = time(0);	de.atime = time(0);	de.mode = ModeDir | 0555; 	tag = tagGen();	addr = blockAlloc(BtData, tag); 	/* build up meta block */	memset(buf, 0, bsize);	mbInit(&mb, buf, bsize, bsize/100);	me.size = deSize(&de);	me.p = mbAlloc(&mb, me.size);	assert(me.p != nil);	dePack(&de, &me);	mbInsert(&mb, 0, &me);	mbPack(&mb);	blockWrite(PartData, addr);	deCleanup(&de); 	/* build up entry for meta block */	entryInit(e);	e->flags |= VtEntryLocal; 	e->size = bsize;	e->tag = tag;	localToGlobal(addr, e->score);} static u32introotInit(Entry *e){	ulong addr;	u32int tag; 	tag = tagGen(); 	addr = blockAlloc(BtDir, tag);	memset(buf, 0, bsize); 	/* root meta data is in the third entry */	entryPack(e, buf, 2); 	entryInit(e);	e->flags |= VtEntryDir;	entryPack(e, buf, 0); 	entryInit(e);	entryPack(e, buf, 1); 	blockWrite(PartData, addr); 	entryInit(e);	e->flags |= VtEntryLocal|VtEntryDir; 	e->size = VtEntrySize*3;	e->tag = tag;	localToGlobal(addr, e->score); 	addr = blockAlloc(BtDir, RootTag);	memset(buf, 0, bsize);	entryPack(e, buf, 0); 	blockWrite(PartData, addr); 	return addr;}  static u32intblockAlloc(int type, u32int tag){	static u32int addr;	Label l;	int lpb; 	lpb = bsize/LabelSize; 	blockRead(PartLabel, addr/lpb);	if(!labelUnpack(&l, buf, addr % lpb))		vtFatal("bad label: %r");	if(l.state != BsFree)		vtFatal("want to allocate block already in use");	l.epoch = 1;	l.epochClose = ~(u32int)0;	l.type = type;	l.state = BsAlloc;	l.tag = tag;	labelPack(&l, buf, addr % lpb);	blockWrite(PartLabel, addr/lpb);	return addr++;} static voidsuperInit(char *label, u32int root, uchar score[VtScoreSize]){	Super s; 	memset(buf, 0, bsize);	memset(&s, 0, sizeof(s));	s.version = SuperVersion;	s.epochLow = 1;	s.epochHigh = 1;	s.qid = qid;	s.active = root;	s.next = NilBlock;	s.current = NilBlock;	strecpy(s.name, s.name+sizeof(s.name), label);	memmove(s.last, score, VtScoreSize); 	superPack(&s, buf);	blockWrite(PartSuper, 0);} static u64intunittoull(char *s){	char *es;	u64int n; 	if(s == nil)		return TWID64;	n = strtoul(s, &es, 0);	if(*es == 'k' || *es == 'K'){		n *= 1024;		es++;	}else if(*es == 'm' || *es == 'M'){		n *= 1024*1024;		es++;	}else if(*es == 'g' || *es == 'G'){		n *= 1024*1024*1024;		es++;	}	if(*es != '\0')		return TWID64;	return n;} static voidblockRead(int part, u32int addr){	if(!diskReadRaw(disk, part, addr, buf))		vtFatal("read failed: %r");} static voidblockWrite(int part, u32int addr){	if(!diskWriteRaw(disk, part, addr, buf))		vtFatal("write failed: %r");} static voidaddFile(File *root, char *name, uint mode){	File *f; 	f = fileCreate(root, name, mode | ModeDir, "adm");	if(f == nil)		vtFatal("could not create file: %s: %r", name);	fileDecRef(f);} static voidtopLevel(char *name){	Fs *fs;	File *root; 	/* ok, now we can open as a fs */	fs = fsOpen(name, z, 100, OReadWrite);	if(fs == nil)		vtFatal("could not open file system: %r");	vtRLock(fs->elk);	root = fsGetRoot(fs);	if(root == nil)		vtFatal("could not open root: %r");	addFile(root, "active", 0555);	addFile(root, "archive", 0555);	addFile(root, "snapshot", 0555);	fileDecRef(root);	if(iso9660file)		iso9660copy(fs);	vtRUnlock(fs->elk);	fsClose(fs);} static intventiRead(uchar score[VtScoreSize], int type){	int n; 	n = vtRead(z, score, type, buf, bsize);	if(n < 0)		vtFatal("ventiRead %V (%d) failed: %R", score, type);	vtZeroExtend(type, buf, n, bsize);	return n;} static u32intventiRoot(char *host, char *s){	int i, n;	uchar score[VtScoreSize];	u32int addr, tag;	DirEntry de;	MetaBlock mb;	MetaEntry me;	Entry e;	VtRoot root; 	if(!parseScore(score, s))		vtFatal("bad score '%s'", s); 	if((z = vtDial(host, 0)) == nil	|| !vtConnect(z, nil))		vtFatal("connect to venti: %R"); 	tag = tagGen();	addr = blockAlloc(BtDir, tag); 	ventiRead(score, VtRootType);	if(!vtRootUnpack(&root, buf))		vtFatal("corrupted root: vtRootUnpack");	n = ventiRead(root.score, VtDirType); 	/*	 * Fossil's vac archives start with an extra layer of source,

Lines 1–500 of 580.