⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devtinyfs.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
字号:
/* *  a pity the code isn't also tiny... */#include "u.h"#include "../port/lib.h"#include "../port/error.h"#include "mem.h"#include "dat.h"#include "fns.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[NAMELEN];	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;};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(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 = Notapin;  // what is a 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){	char dbuf[DIRLEN];	Dir d;	uchar buf[Blen];	ulong x, bno;	int n, done;	Tfile *f;	Mdir *mdir;	Mdata *mdata;	devtab[fs->c->type]->stat(fs->c, dbuf);	convM2D(dbuf, &d);	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);	memset(fs->map, 0x0, x);	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, Dirtab *tab, int ntab, int i, Dir *dp){	Tfs *fs;	Tfile *f;	Qid qid;	USED(ntab);	USED(tab);	qid.vers = 0;	fs = &tinyfs.fs[c->dev];	if(i >= fs->nf)		return -1;	if(i == DEVDOTDOT){		qid.path = CHDIR;		devdir(c, qid, ".", 0, eve, 0555, dp);		return 1;	}	f = &fs->f[i];	if(f->name[0] == 0)		return 0;	qid.path = i;	devdir(c, qid, f->name, f->length, eve, 0775, dp);	return 1;}static voidtinyfsinit(void){	if(Nlen > NAMELEN)		panic("tinyfsinit");}/* *  specifier is an open file descriptor */static Chan*tinyfsattach(char *spec){	Tfs *fs;	Chan *c;	volatile struct { Chan *cc; } rock;	int i;	char buf[NAMELEN*2];	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))			break;		qunlock(&fs->ql);	}	if(i < Maxfs){		fs->r++;		qunlock(&fs->ql);		cclose(rock.cc);	} else {		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){			qlock(&fs->ql);			if(fs->r == 0)				break;			qunlock(&fs->ql);		}		if(fs == &tinyfs.fs[Maxfs])			error("too many tinyfs's");		fs->c = rock.cc;		fs->r = 1;		fs->f = 0;		fs->nf = 0;		fs->fsize = 0;		tfsinit(fs);		qunlock(&fs->ql);	}	poperror();	c = devattach('F', spec);	c->dev = fs - tinyfs.fs;	c->qid.path = CHDIR;	c->qid.vers = 0;	return c;}static Chan*tinyfsclone(Chan *c, Chan *nc){	Tfs *fs;	fs = &tinyfs.fs[c->dev];	qlock(&fs->ql);	fs->r++;	qunlock(&fs->ql);	return devclone(c, nc);}static inttinyfswalk(Chan *c, char *name){	int n;	Tfs *fs;	fs = &tinyfs.fs[c->dev];	qlock(&fs->ql);	n = devwalk(c, name, 0, 0, tinyfsgen);	if(n != 0 && c->qid.path != CHDIR){		fs = &tinyfs.fs[c->dev];		fs->f[c->qid.path].r++;	}	qunlock(&fs->ql);	return n;}static voidtinyfsstat(Chan *c, char *db){	devstat(c, db, 0, 0, tinyfsgen);}static Chan*tinyfsopen(Chan *c, int omode){	Tfile *f;	volatile struct { Tfs *fs; } rock;	rock.fs = &tinyfs.fs[c->dev];	if(c->qid.path & CHDIR){		if(omode != OREAD)			error(Eperm);	} else {		qlock(&rock.fs->ql);		if(waserror()){			qunlock(&rock.fs->ql);			nexterror();		}		switch(omode){		case OTRUNC|ORDWR:		case OTRUNC|OWRITE:			f = newfile(rock.fs, rock.fs->f[c->qid.path].name);			rock.fs->f[c->qid.path].r--;			c->qid.path = f - rock.fs->f;			break;		case OREAD:		case OEXEC:			break;		default:			error(Eperm);		}		qunlock(&rock.fs->ql);		poperror();	}	return devopen(c, omode, 0, 0, tinyfsgen);}static voidtinyfscreate(Chan *c, char *name, int omode, ulong perm){	volatile struct { Tfs *fs; } rock;	Tfile *f;	USED(perm);	rock.fs = &tinyfs.fs[c->dev];	qlock(&rock.fs->ql);	if(waserror()){		qunlock(&rock.fs->ql);		nexterror();	}	f = newfile(rock.fs, name);	qunlock(&rock.fs->ql);	poperror();	c->qid.path = f - rock.fs->f;	c->qid.vers = 0;	c->mode = openmode(omode);}static voidtinyfsremove(Chan *c){	Tfs *fs;	Tfile *f;	if(c->qid.path == CHDIR)		error(Eperm);	fs = &tinyfs.fs[c->dev];	f = &fs->f[c->qid.path];	qlock(&fs->ql);	freefile(fs, f, Notabno);	qunlock(&fs->ql);}static voidtinyfsclose(Chan *c){	volatile struct { Tfs *fs; } rock;	Tfile *f, *nf;	int i;	rock.fs = &tinyfs.fs[c->dev];	qlock(&rock.fs->ql);	/* dereference file and remove old versions */	if(!waserror()){		if(c->qid.path != CHDIR){			f = &rock.fs->f[c->qid.path];			f->r--;			if(f->r == 0){				if(f->flag & Frmonclose)					freefile(rock.fs, f, Notabno);				else if(f->flag & Fcreating){					/* remove all other files with this name */					for(i = 0; i < rock.fs->fsize; i++){						nf = &rock.fs->f[i];						if(f == nf)							continue;						if(strcmp(nf->name, f->name) == 0){							if(nf->r)								nf->flag |= Frmonclose;							else								freefile(rock.fs, nf, Notabno);						}					}					f->flag &= ~Fcreating;				}			}		}		poperror();	}	/* dereference rock.fs and remove on zero refs */	rock.fs->r--;	if(rock.fs->r == 0){		if(rock.fs->f)			free(rock.fs->f);		rock.fs->f = 0;		rock.fs->nf = 0;		rock.fs->fsize = 0;		if(rock.fs->map)			free(rock.fs->map);		rock.fs->map = 0;		cclose(rock.fs->c);		rock.fs->c = 0;	}	qunlock(&rock.fs->ql);}static longtinyfsread(Chan *c, void *a, long n, vlong offset){	volatile struct { Tfs *fs; } rock;	Tfile *f;	int sofar, i, off;	ulong bno;	Mdata *md;	uchar buf[Blen];	uchar *p;	if(c->qid.path & CHDIR)		return devdirread(c, a, n, 0, 0, tinyfsgen);	p = a;	rock.fs = &tinyfs.fs[c->dev];	f = &rock.fs->f[c->qid.path];	if(offset >= f->length)		return 0;	qlock(&rock.fs->ql);	if(waserror()){		qunlock(&rock.fs->ql);		nexterror();	}	if(n + offset >= f->length)		n = f->length - offset;	/* walk to starting data block */	if(0 && f->finger <= offset && f->fbno != Notabno){		sofar = f->finger;		bno = f->fbno;	} else {		sofar = 0;		bno = f->dbno;	}	for(; sofar + Dlen <= offset; sofar += Dlen){		md = readdata(rock.fs, bno, buf, 0);		if(md == 0)			error(Eio);		bno = GETS(md->bno);	}	/* read data */	off = offset%Dlen;	offset -= off;	for(sofar = 0; sofar < n; sofar += i){		md = readdata(rock.fs, bno, buf, &i);		if(md == 0)			error(Eio);		/* update finger for successful read */		f->finger = offset;		f->fbno = bno;		offset += Dlen;		i -= off;		if(i > n - sofar)			i = n - sofar;		memmove(p, md->data+off, i);		p += i;		bno = GETS(md->bno);		off = 0;	}	qunlock(&rock.fs->ql);	poperror();	return sofar;}/* *  if we get a write error in this routine, blocks will *  be lost.  They should be recovered next fsinit. */static longtinyfswrite(Chan *c, void *a, long n, vlong offset){	Tfile *f;	int last, next, i, finger, off, used;	ulong bno, fbno;	Mdata *md;	uchar buf[Blen];	uchar *p;	volatile struct {		Tfs *fs;		ulong dbno;	} rock;	if(c->qid.path & CHDIR)		error(Eperm);	if(n == 0)		return 0;	p = a;	rock.fs = &tinyfs.fs[c->dev];	f = &rock.fs->f[c->qid.path];	qlock(&rock.fs->ql);	rock.dbno = Notabno;	if(waserror()){		freeblocks(rock.fs, rock.dbno, Notabno);		qunlock(&rock.fs->ql);		nexterror();	}	/* files are append only, anything else is illegal */	if(offset != f->length)		error("append only");	/* write blocks backwards */	p += n;	last = offset + n;	fbno = Notabno;	finger = 0;	off = offset; /* so we have something signed to compare against */	for(next = ((last-1)/Dlen)*Dlen; next >= off; next -= Dlen){		bno = mapalloc(rock.fs);		if(bno == Notabno)			error("out of space");		i = last - next;		p -= i;		if(last == n+offset){			writedata(rock.fs, bno, rock.dbno, p, i, 1);			finger = next;	/* remember for later */			fbno = bno;		} else {			writedata(rock.fs, bno, rock.dbno, p, i, 0);		}		rock.dbno = bno;		last = next;	}	/* walk to last data block */	md = (Mdata*)buf;	if(0 && f->finger < offset && f->fbno != Notabno){		next = f->finger;		bno = f->fbno;	} else {		next = 0;		bno = f->dbno;	}	used = 0;	while(bno != Notabno){		md = readdata(rock.fs, bno, buf, &used);		if(md == 0)			error(Eio);		if(md->type == Tagend){			if(next + Dlen < offset)				panic("devtinyfs1");			break;		}		next += Dlen;		if(next > offset)			panic("devtinyfs1");		bno = GETS(md->bno);	}	/* point to new blocks */	if(offset == 0){		/* first block in a file */		f->dbno = rock.dbno;		writedir(rock.fs, f);	} else {		/* updating a current block */		i = last - offset;		if(i > 0){			p -= i;			memmove(md->data + used, p, i);			used += i;		}		writedata(rock.fs, bno, rock.dbno, md->data, used, last == n+offset);	}	f->length += n;	/* update finger */	if(fbno != Notabno){		f->finger = finger;		f->fbno =  fbno;	}	poperror();	qunlock(&rock.fs->ql);	return n;}Dev tinyfsdevtab = {	'F',	"tinyfs",	devreset,	tinyfsinit,	tinyfsattach,	tinyfsclone,	tinyfswalk,	tinyfsstat,	tinyfsopen,	tinyfscreate,	tinyfsclose,	tinyfsread,	devbread,	tinyfswrite,	devbwrite,	tinyfsremove,	devwstat,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -