plan 9 kernel history: overview | file list | diff list

1996/0206/port/devtinyfs.c (diff list | history)

port/devtinyfs.c on 1996/0116
1996/0116    
/* 
1996/0202    
 *  a pity the code isn't also tiny... 
1996/0116    
 */ 
 
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"devtab.h" 
 
enum{ 
	Qdir, 
1996/0120    
	Qmedium, 
1996/0123    
 
1996/0201    
	Maxfs=		10,	/* max file systems */ 
1996/0131    
 
1996/0201    
	Blen=		48,	/* block length */ 
	Nlen=		28,	/* name length */ 
	Dlen=		Blen - 4, 
 
	Tagdir=		'd', 
	Tagdata=	'D', 
	Tagend=		'e', 
	Tagfree=	'f', 
 
1996/0202    
	Notapin=		0xffff, 
	Notabno=		0xffff, 
1996/0203    
 
	Fcreating=	1, 
	Frmonclose=	2, 
1996/0116    
}; 
 
1996/0202    
/* representation of a Tdir on medium */ 
1996/0201    
typedef struct Mdir Mdir; 
struct Mdir { 
	uchar	type; 
	uchar	bno[2]; 
	uchar	pin[2]; 
	char	name[Nlen]; 
	char	pad[Blen - Nlen - 6]; 
	uchar	sum; 
}; 
 
1996/0202    
/* representation of a Tdata/Tend on medium */ 
1996/0201    
typedef struct Mdata Mdata; 
struct Mdata { 
	uchar	type; 
	uchar	bno[2]; 
	char	data[Dlen]; 
	uchar	sum; 
}; 
 
typedef struct Tfile Tfile; 
struct Tfile { 
1996/0206    
	Lock; 
1996/0202    
	int	r; 
1996/0201    
	char	name[NAMELEN]; 
	ushort	bno; 
	ushort	dbno; 
	ushort	pin; 
1996/0203    
	uchar	flag; 
1996/0201    
	ulong	length; 
}; 
 
typedef struct Tfs Tfs; 
struct Tfs { 
1996/0202    
	QLock; 
1996/0201    
	int	r; 
1996/0116    
	Chan	*c; 
1996/0131    
	uchar	*map; 
	int	nblocks; 
1996/0201    
	Tfile	*f; 
	int	nf; 
	int	fsize; 
1996/0122    
}; 
 
struct { 
	QLock; 
1996/0201    
	Tfs	fs[Maxfs]; 
	short	nfs; 
1996/0116    
} tinyfs; 
 
1996/0131    
#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 uchar 
checksum(uchar *p) 
{ 
	uchar *e; 
	uchar s; 
1996/0123    
 
1996/0131    
	s = 0; 
	for(e = p + Blen; p < e; p++) 
		s += *p; 
1996/0202    
	return s; 
1996/0131    
} 
1996/0123    
 
1996/0131    
static void 
1996/0201    
mapclr(Tfs *fs, ulong bno) 
1996/0131    
{ 
	fs->map[bno>>3] &= ~(1<<(bno&7)); 
} 
 
static void 
1996/0201    
mapset(Tfs *fs, ulong bno) 
1996/0131    
{ 
	fs->map[bno>>3] |= 1<<(bno&7); 
} 
 
static int 
1996/0201    
isalloced(Tfs *fs, ulong bno) 
1996/0131    
{ 
1996/0201    
	return fs->map[bno>>3] & (1<<(bno&7)); 
} 
 
static int 
mapalloc(Tfs *fs) 
{ 
1996/0131    
	int i, j, lim; 
	uchar x; 
 
	qlock(fs); 
	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); 
				qunlock(fs); 
				return i*8 + j; 
			} 
	} 
	qunlock(fs); 
	return -1; 
} 
 
1996/0201    
static Mdir* 
validdir(Tfs *fs, uchar *p) 
{ 
	Mdir *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
	if(buf[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) 
{ 
	Mdata *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
	md = (Mdir*)p; 
	switch(buf[0]){ 
	case Tagdata: 
		x = GETS(md->bno); 
		if(x >= fs->nblocks) 
			return 0; 
		break; 
	case Tagend: 
		x = GETS(md->bno); 
		if(x > Blen - 4) 
			return 0; 
		break; 
	} 
	return md; 
} 
 
1996/0206    
static Mdata* 
readdata(Tfs *fs, ulong bno, uchar *buf) 
{ 
	if(bno >= fs->nblocks) 
		return 0; 
	n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
	if(n != Blen) 
		return 0; 
	return validdata(fs, buf); 
} 
 
1996/0202    
static int 
writedir(Tfs *fs, Tfile *f) 
{ 
	Mdir *md; 
	int n; 
	uchar buf[Blen]; 
 
	if(f->bno == Notabno) 
		return Blen; 
 
	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); 
	f->sum = 0 - checksum(buf); 
 
	return devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
} 
 
1996/0201    
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
{ 
	uchar buf[Blen]; 
	ulong bno; 
	int n; 
	Mdata *md; 
 
	/* remove blocks from map */ 
	bno = f->dbno; 
1996/0202    
	while(bno != bend && bno != Notabno){ 
1996/0201    
		mapclr(fs, bno); 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
		md = validdata(buf); 
		if(md == 0) 
			break; 
		if(md->type == Tagend) 
			break; 
		bno = GETS(md->bno); 
	} 
 
	/* change file type to free on medium */ 
1996/0202    
	if(f->bno != Notabno){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno); 
		if(n != Blen) 
			return; 
		buf[0] = Tagfree; 
		devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); 
	} 
1996/0201    
 
	/* forget we ever knew about it */ 
	memset(f, 0, sizeof(*f)); 
} 
 
static void 
expand(Tfs *fs) 
{ 
	Tfile *f; 
 
	fs->fsize += 8; 
	f = smalloc(fs->fsize*sizeof(*f)); 
 
	memmove(f, fs->f, fs->nf*sizoef(f)); 
	free(fs->f); 
	fs->f = f; 
} 
 
1996/0202    
static Tfile* 
newfile(Tfs *fs, char *name) 
{ 
	int i; 
	Tfile *f; 
 
	/* find free entry in file table */ 
	for(;;) { 
		for(i = 0; i < fs->fsize; i++){ 
			f = &fs->f[i]; 
			if(f->name[0] == 0){ 
				strncpy(f->name, name, sizeof(f->name)-1); 
				break; 
			} 
		} 
 
		if(i < fs->fsize) 
			break; 
 
		expand(fs); 
	} 
 
1996/0203    
	f->flag = Fcreating; 
1996/0202    
	f->dbno = Notabno; 
	f->bno = mapalloc(fs); 
 
	/* write directory block */ 
	if(waserror()){ 
		filefree(fs, f, Notabno); 
		nexterror(); 
	} 
	if(b->bno == Notabno) 
		error("out of space"); 
	writedir(fs, f); 
	poperror(); 
	 
	return f; 
} 
 
1996/0123    
/* 
1996/0202    
 *  Read the whole medium and build a file table and used 
 *  block bitmap.  Inconsistent files are purged. 
1996/0123    
 */ 
1996/0201    
static void 
fsinit(Tfs *fs) 
1996/0123    
{ 
1996/0131    
	uchar buf[Blen+DIRLEN]; 
1996/0123    
	Dir d; 
1996/0131    
	ulong x, bno; 
1996/0201    
	int n; 
	Tfile *f; 
	Mdir *mdir; 
	Mdata *mdat; 
1996/0123    
 
	devtab[fs->c->type].stat(fs->c, buf); 
	convM2D(buf, &d); 
1996/0131    
	fs->nblocks = d.length/Blen; 
	if(fs->nblocks < 3) 
1996/0123    
		error("tinyfs medium too small"); 
 
1996/0131    
	/* bitmap for block usage */ 
	x = (fs->nblocks + 8 - 1)/8; 
1996/0201    
	fs->map = smalloc(x); 
1996/0131    
	memset(fs->map, 0x0, x); 
	for(bno = fs->nblocks; bno < x*8; bno++) 
		mapset(fs, bno); 
1996/0123    
 
1996/0201    
	/* find files */ 
1996/0131    
	for(bno = 0; bno < fs->nblocks; bno++){ 
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); 
		if(n != Blen) 
			break; 
1996/0201    
 
		mdir = validdir(buf); 
		if(mdir == 0) 
1996/0131    
			continue; 
1996/0201    
 
		if(fs->nfs <= fs->fsize) 
			expand(fs); 
1996/0202    
 
1996/0201    
		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; 
	} 
 
	/* follow files */ 
	for(f = fs->f; f; f = f->next){ 
		bno = fs->dbno; 
		for(;;) { 
			if(isalloced(fs, bno)){ 
				freefile(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); 
			if(mdata == 0){ 
				freefile(fs, f, bno); 
				break; 
			} 
1996/0131    
			mapset(fs, bno); 
1996/0201    
			switch(mdata->type){ 
			case Tagdata: 
				bno = GETS(mdata->bno); 
				f->len += Dlen; 
				break; 
			case Tagend: 
				f->len += GETS(mdata->bno); 
				break; 
			} 
1996/0131    
		} 
	} 
1996/0123    
} 
 
1996/0202    
/* 
 *  single directory 
 */ 
1996/0201    
static int 
tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 
1996/0123    
{ 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
	Qid qid; 
1996/0123    
 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
		return -1; 
	f = &fs->f[i]; 
	qid.path = i; 
	qid.vers = 0; 
1996/0202    
	devdir(c, qid, f->name, f->length, eve, 0664, dp); 
1996/0201    
	return 1; 
1996/0123    
} 
 
1996/0201    
void 
tinyfsreset(void) 
{ 
	if(Nlen > NAMELEN) 
		panic("tinyfsreset"); 
} 
 
void 
tinyfsinit(void) 
{ 
} 
 
1996/0116    
Chan * 
tinyfsattach(char *spec) 
{ 
1996/0201    
	Tfs *fs; 
1996/0122    
	Chan *c, *cc; 
1996/0201    
	int i; 
1996/0120    
 
1996/0122    
	cc = namec((char*)arg[0], Aopen, arg[1], 0); 
1996/0123    
	if(waserror()){ 
		close(cc); 
1996/0201    
		qunlock(&tinyfs); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1996/0122    
	qlock(&tinyfs); 
1996/0201    
	for(i = 0; i < tinyfs.nfs; i++){ 
		fs = &tinyfs.fs[i]; 
		if(fs && eqchan(c, fs->c)) 
1996/0122    
			break; 
	} 
1996/0201    
	if(i < tinyfs.nfs){ 
1996/0202    
		qlock(fs); 
1996/0201    
		fs->r++; 
1996/0202    
		qunlock(fs); 
1996/0122    
		close(cc); 
	} else { 
1996/0201    
		if(tinyfs.nfs >= Maxfs) 
			error("too many tinyfs's"); 
		fs = &tinyfs.fs[tinyfs.nfs]; 
		memset(fs, 0, sizeof(*fs)); 
1996/0122    
		fs->c = cc; 
1996/0201    
		fs->r = 1; 
		fsinit(fs); 
		tinyfs.nfs++; 
1996/0122    
	} 
1996/0201    
	qunlock(&tinyfs); 
1996/0123    
	poperror(); 
1996/0122    
 
1996/0201    
	c = devattach('U', spec); 
	c->dev = fs - tinyfs.fs; 
	c->qid.path = CHDIR; 
	c->qid.vers = 0; 
1996/0122    
 
	return c; 
1996/0116    
} 
 
Chan * 
tinyfsclone(Chan *c, Chan *nc) 
{ 
1996/0202    
	qlock(fs); 
	fs->r++; 
	qunlock(fs); 
 
1996/0116    
	return devclone(c, nc); 
} 
 
int 
tinyfswalk(Chan *c, char *name) 
{ 
1996/0202    
	int n; 
 
	qlock(fs); 
	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); 
	return n; 
1996/0116    
} 
 
void 
tinyfsstat(Chan *c, char *db) 
{ 
1996/0201    
	devstat(c, db, 0, 0, tinyfsgen); 
1996/0116    
} 
 
Chan * 
tinyfsopen(Chan *c, int omode) 
{ 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
 
	fs = &tinyfs.fs[c->dev]; 
 
	if(c->path & CHDIR){ 
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
1996/0202    
		qlock(fs); 
		if(omode == (OTRUNC|ORDWR)){ 
			f = newfile(fs, fs->f[c->qid.path]); 
			c->qid.path = f - fs->f; 
		} else if(omode != OREAD){ 
			qunlock(fs); 
			error(Eperm); 
1996/0201    
		} 
1996/0202    
		qunlock(fs); 
1996/0201    
	} 
 
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0116    
} 
 
void 
tinyfscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1996/0201    
	Tfs *fs; 
	Tfile *f; 
1996/0116    
 
	if(perm & CHDIR) 
		error("directory creation illegal"); 
 
1996/0202    
	qlock(fs); 
	f = newfile(fs, name); 
	qunlock(fs); 
1996/0201    
 
	c->qid.path = f - fs->f; 
1996/0202    
	c->qid.vers = 0; 
1996/0116    
	c->mode = openmode(omode); 
} 
 
void 
tinyfsremove(Chan *c) 
{ 
	USED(c); 
	error(Eperm); 
} 
 
void 
tinyfswstat(Chan *c, char *dp) 
{ 
	USED(c, dp); 
	error(Eperm); 
} 
 
void 
tinyfsclose(Chan *c) 
{ 
1996/0201    
	Tfs *fs, **l; 
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
	fs = c->aux; 
 
1996/0202    
	qlock(fs); 
1996/0201    
 
1996/0202    
	/* dereference file and remove old versions */ 
	if(c->qid.path != CHDIR){ 
		f = &fs->f[c->qid.path]; 
		f->r--; 
1996/0203    
		if(f->r == 0){ 
			if(f->creating){ 
				/* remove all other files with this name */ 
				for(i = 0; i < fs->fsize; i++){ 
					nf = &fs->f[i]; 
					if(f == nf) 
						continue; 
					if(strcmp(nf->name, f->name) == 0){ 
						if(nf->r) 
							nf->flag |= Frmonclose; 
						else 
							freefile(fs, nf, Notabno); 
					} 
				} 
				f->flag &= ~(Frmonclose|Fcreating); 
1996/0202    
			} 
1996/0203    
			if(f->flag & Frmonclose){ 
				freefile(fs, f, Notabno); 
1996/0202    
		} 
	} 
 
	/* dereference fs and remove on zero refs */ 
	fs->r--; 
1996/0203    
	unlock(fs); 
	qlock(&tinyfs); 
1996/0201    
	if(fs->ref == 0){ 
		for(l = &fs->l; *l;){ 
			if(*l == fs){ 
				*l = fs->next; 
				break; 
			} 
			l = &(*l)->next; 
		} 
1996/0203    
		free(fs-f); 
1996/0201    
		free(fs->map); 
		close(fs->c); 
1996/0203    
		memset(fs, 0, sizeof(*fs)); 
1996/0201    
	} 
	qunlock(&tinyfs); 
1996/0116    
} 
 
long 
tinyfsread(Chan *c, void *a, long n, ulong offset) 
{ 
1996/0203    
	Tfs *fs; 
	Tfile *f; 
	int sofar, i; 
1996/0206    
	ulong bno, tbno; 
	Mdata *md; 
	uchar buf[Blen]; 
1996/0203    
 
	if(c->qid.path & CHDIR) 
1996/0201    
		return devdirread(c, a, n, tinyfstab, Ntinyfstab, tinyfsgen); 
1996/0203    
 
	fs = tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
	if(offset >= f->length) 
		return 0; 
	if(n + offset >= f->length) 
		n = f->length - offset; 
1996/0206    
 
	/* walk to first data block */ 
	bno = f->dbno; 
	for(sofar = 0; sofar < offset; sofar += Blen){ 
		md = readdata(fs, bno, buf); 
		if(md == 0) 
			error(Eio); 
		bno = GETS(md->bno); 
	} 
 
	/* read first block */ 
	i = offset%Blen; 
 
	/* read data */ 
	for(sofar = 0; sofar+Blen < offset; sofar += Blen){ 
	 
1996/0203    
 
1996/0116    
	return n; 
} 
 
Block* 
tinyfsbread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
 
long 
tinyfswrite(Chan *c, char *a, long n, ulong offset) 
{ 
	if(waserror()){ 
		qunlock(&tinyfs); 
		nexterror(); 
	} 
	qlock(&tinyfs); 
	qunlock(&tinyfs); 
 
	switch(c->qid.path & ~CHDIR){ 
	case Qdata: 
		break; 
	default: 
		error(Ebadusefd); 
	} 
	return n; 
} 
 
long 
tinyfsbwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)