Charles.Forsyth20060303a828770d19 years agoHistory
895 lines · 15.0 KB · C
RawDownload
#include	"dat.h"#include	"fns.h"#include	"error.h"  enum{	Qdir,	Qmedium, 	Maxfs=		10,	/* max file systems */ 	Blen=		48,	/* block length */	Nlen=		28,	/* name length */	Dlen=		Blen - 4, 	Tagdir=		'd',	Tagdata=	'D',	Tagend=		'e',	Tagfree=	'f', 	Notapin=		0xffff,	Notabno=		0xffff, 	Fcreating=	1,	Frmonclose=	2}; /* representation of a Tdir on medium */typedef struct Mdir Mdir;struct Mdir {	uchar	type;	uchar	bno[2];	uchar	pin[2];	char	name[Nlen];	char	pad[Blen - Nlen - 6];	uchar	sum;}; /* representation of a Tdata/Tend on medium */typedef struct Mdata Mdata;struct Mdata {	uchar	type;	uchar	bno[2];	uchar	data[Dlen];	uchar	sum;}; typedef struct Tfile Tfile;struct Tfile {	int	r;	char	name[Nlen];	ushort	bno;	ushort	dbno;	ushort	pin;	uchar	flag;	ulong	length; 	/* hint to avoid egregious reading */	ushort	fbno;	ulong	finger;}; typedef struct Tfs Tfs;struct Tfs {	QLock	ql;	int	r;	Chan	*c;	uchar	*map;	int	nblocks;	Tfile	*f;	int	nf;	int	fsize;}; static struct {	Tfs	fs[Maxfs];} tinyfs; #define GETS(x) ((x)[0]|((x)[1]<<8))#define PUTS(x, v) {(x)[0] = (v);(x)[1] = ((v)>>8);} #define GETL(x) (GETS(x)|(GETS(x+2)<<16))#define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)}; static ucharchecksum(uchar *p){	uchar *e;	uchar s; 	s = 0;	for(e = p + Blen; p < e; p++)		s += *p;	return s;} static voidmapclr(Tfs *fs, ulong bno){	fs->map[bno>>3] &= ~(1<<(bno&7));} static voidmapset(Tfs *fs, ulong bno){	fs->map[bno>>3] |= 1<<(bno&7);} static intisalloced(Tfs *fs, ulong bno){	return fs->map[bno>>3] & (1<<(bno&7));} static intmapalloc(Tfs *fs){	int i, j, lim;	uchar x; 	lim = (fs->nblocks + 8 - 1)/8;	for(i = 0; i < lim; i++){		x = fs->map[i];		if(x == 0xff)			continue;		for(j = 0; j < 8; j++)			if((x & (1<<j)) == 0){				fs->map[i] = x|(1<<j);				return i*8 + j;			}	} 	return Notabno;} static Mdir*validdir(Tfs *fs, uchar *p){	Mdir *md;	ulong x; 	if(checksum(p) != 0)		return 0;	if(p[0] != Tagdir)		return 0;	md = (Mdir*)p;	x = GETS(md->bno);	if(x >= fs->nblocks)		return 0;	return md;} static Mdata*validdata(Tfs *fs, uchar *p, int *lenp){	Mdata *md;	ulong x; 	if(checksum(p) != 0)		return 0;	md = (Mdata*)p;	switch(md->type){	case Tagdata:		x = GETS(md->bno);		if(x >= fs->nblocks)			return 0;		if(lenp)			*lenp = Dlen;		break;	case Tagend:		x = GETS(md->bno);		if(x > Dlen)			return 0;		if(lenp)			*lenp = x;		break;	default:		return 0;	}	return md;} static Mdata*readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp){	if(bno >= fs->nblocks)		return 0;	if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen)		error(Eio);	return validdata(fs, buf, lenp);} static voidwritedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last){	Mdata md; 	if(bno >= fs->nblocks)		error(Eio);	if(len > Dlen)		len = Dlen;	if(len < 0)		error(Eio);	memset(&md, 0, sizeof(md));	if(last){		md.type = Tagend;		PUTS(md.bno, len);	} else {		md.type = Tagdata;		PUTS(md.bno, next);	}	memmove(md.data, buf, len);	md.sum = 0 - checksum((uchar*)&md);		if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen)		error(Eio);} static voidwritedir(Tfs *fs, Tfile *f){	Mdir *md;	uchar buf[Blen]; 	if(f->bno == Notabno)		return; 	md = (Mdir*)buf;	memset(buf, 0, Blen);	md->type = Tagdir;	strncpy(md->name, f->name, sizeof(md->name)-1);	PUTS(md->bno, f->dbno);	PUTS(md->pin, f->pin);	md->sum = 0 - checksum(buf);		if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen)		error(Eio);} static voidfreeblocks(Tfs *fs, ulong bno, ulong bend){	uchar buf[Blen];	Mdata *md; 	if(waserror())		return; 	while(bno != bend && bno != Notabno){		mapclr(fs, bno);		if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen)			break;		md = validdata(fs, buf, 0);		if(md == 0)			break;		if(md->type == Tagend)			break;		bno = GETS(md->bno);	} 	poperror();} static voidfreefile(Tfs *fs, Tfile *f, ulong bend){	uchar buf[Blen]; 	/* remove blocks from map */	freeblocks(fs, f->dbno, bend); 	/* change file type to free on medium */	if(f->bno != Notabno){		memset(buf, 0x55, Blen);		devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno);		mapclr(fs, f->bno);	} 	/* forget we ever knew about it */	memset(f, 0, sizeof(*f));} static voidexpand(Tfs *fs){	Tfile *f; 	fs->fsize += 8;	f = malloc(fs->fsize*sizeof(*f));	if(f == nil)		error(Enomem); 	if(fs->f){		memmove(f, fs->f, fs->nf*sizeof(*f));		free(fs->f);	}	fs->f = f;} static Tfile*newfile(Tfs *fs, char *name){	int i;	volatile struct {		Tfile *f;		Tfs *fs;	} rock; 	/* find free entry in file table */	rock.f = 0;	rock.fs = fs;	for(;;) {		for(i = 0; i < rock.fs->fsize; i++){			rock.f = &rock.fs->f[i];			if(rock.f->name[0] == 0){				strncpy(rock.f->name, name, sizeof(rock.f->name)-1);				break;			}		} 		if(i < rock.fs->fsize){			if(i >= rock.fs->nf)				rock.fs->nf = i+1;			break;		} 		expand(rock.fs);	} 	rock.f->flag = Fcreating;	rock.f->dbno = Notabno;	rock.f->bno = mapalloc(rock.fs);	rock.f->fbno = Notabno;	rock.f->r = 1;	rock.f->pin = up->env->pgrp->pin; 	/* write directory block */	if(waserror()){		freefile(rock.fs, rock.f, Notabno);		nexterror();	}	if(rock.f->bno == Notabno)		error("out of space");	writedir(rock.fs, rock.f);	poperror();		return rock.f;} /* *  Read the whole medium and build a file table and used *  block bitmap.  Inconsistent files are purged.  The medium *  had better be small or this could take a while. */static voidtfsinit(Tfs *fs){	uchar dbuf[STATFIXLEN+32*4];	Dir d;	uchar buf[Blen];	ulong x, bno;	int n, done;	Tfile *f;	Mdir *mdir;	Mdata *mdata; 	n = devtab[fs->c->type]->stat(fs->c, dbuf, sizeof(dbuf));	n = convM2D(dbuf, n, &d, nil);	if(n <= 0)		error("cannot stat tinyfs medium");	fs->nblocks = d.length/Blen;	if(fs->nblocks < 3)		error("tinyfs medium too small"); 	/* bitmap for block usage */	x = (fs->nblocks + 8 - 1)/8;	fs->map = malloc(x);	if(fs->map == nil)		error(Enomem);	for(bno = fs->nblocks; bno < x*8; bno++)		mapset(fs, bno); 	/* find files */	for(bno = 0; bno < fs->nblocks; bno++){		n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno);		if(n != Blen)			break; 		mdir = validdir(fs, buf);		if(mdir == 0)			continue; 		if(fs->nf >= fs->fsize)			expand(fs); 		f = &fs->f[fs->nf++]; 		x = GETS(mdir->bno);		mapset(fs, bno);		strncpy(f->name, mdir->name, sizeof(f->name));		f->pin = GETS(mdir->pin);		f->bno = bno;		f->dbno = x;		f->fbno = Notabno;	} 	/* follow files */	for(f = fs->f; f < &(fs->f[fs->nf]); f++){		bno = f->dbno;		for(done = 0; !done;) {			if(isalloced(fs, bno)){				freefile(fs, f, bno);				break;			}			n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno);			if(n != Blen){				freefile(fs, f, bno);				break;			}			mdata = validdata(fs, buf, 0);			if(mdata == 0){				freefile(fs, f, bno);				break;			}			mapset(fs, bno);			switch(mdata->type){			case Tagdata:				bno = GETS(mdata->bno);				f->length += Dlen;				break;			case Tagend:				f->length += GETS(mdata->bno);				done = 1;				break;			}			if(done)				f->flag &= ~Fcreating;		}	}} /* *  single directory */static inttinyfsgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp){	Tfs *fs;	Tfile *f;	Qid qid; 	USED(name);	USED(ntab);	USED(tab); 	fs = &tinyfs.fs[c->dev];	if(i >= fs->nf)		return -1;	qid.vers = 0;	if(i == DEVDOTDOT){		qid.type = QTDIR;		devdir(c, qid, ".", 0, eve, DMDIR|0555, dp);		return 1;	}	f = &fs->f[i];	if(f->name[0] == 0)		return 0;	qid.path = i+1;	qid.type = QTFILE;	devdir(c, qid, f->name, f->length, eve, 0664, dp);	return 1;} /* *  specifier is the name of a device in /dev */static Chan *tinyfsattach(char *spec){	Tfs *fs;	Chan *c;	volatile struct { Chan *cc; } rock;	int i;	char buf[KNAMELEN*3]; 	if(*spec == 0 || strchr(spec, '/') != nil)		error("bad specifier"); 	snprint(buf, sizeof(buf), "/dev/%s", spec);	rock.cc = namec(buf, Aopen, ORDWR, 0);	if(waserror()){		cclose(rock.cc);		nexterror();	} 	fs = 0;	for(i = 0; i < Maxfs; i++){		fs = &tinyfs.fs[i];		qlock(&fs->ql);		if(fs->r && eqchan(rock.cc, fs->c, 1))

Lines 1–500 of 895.