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

1999/0623/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    
 */ 
1999/0612    
#include "u.h" 
#include "../port/lib.h" 
#include "../port/error.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
1996/0116    
 
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, 
1999/0612    
	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]; 
1996/0220    
	uchar	data[Dlen]; 
1996/0201    
	uchar	sum; 
}; 
 
typedef struct Tfile Tfile; 
struct Tfile { 
1996/0202    
	int	r; 
1996/0201    
	char	name[NAMELEN]; 
	ushort	bno; 
	ushort	dbno; 
	ushort	pin; 
1996/0203    
	uchar	flag; 
1996/0201    
	ulong	length; 
1996/0220    
 
	/* hint to avoid egregious reading */ 
	ushort	fbno; 
	ulong	finger; 
1996/0201    
}; 
 
typedef struct Tfs Tfs; 
struct Tfs { 
1996/0226    
	QLock	ql; 
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 { 
1996/0201    
	Tfs	fs[Maxfs]; 
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; 
 
	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; 
			} 
	} 
1996/0220    
 
	return Notabno; 
1996/0131    
} 
 
1996/0201    
static Mdir* 
validdir(Tfs *fs, uchar *p) 
{ 
	Mdir *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
1996/0218    
	if(p[0] != Tagdir) 
1996/0201    
		return 0; 
	md = (Mdir*)p; 
	x = GETS(md->bno); 
	if(x >= fs->nblocks) 
		return 0; 
	return md; 
} 
 
static Mdata* 
1996/0217    
validdata(Tfs *fs, uchar *p, int *lenp) 
1996/0201    
{ 
	Mdata *md; 
	ulong x; 
 
	if(checksum(p) != 0) 
		return 0; 
1996/0218    
	md = (Mdata*)p; 
	switch(md->type){ 
1996/0201    
	case Tagdata: 
		x = GETS(md->bno); 
		if(x >= fs->nblocks) 
			return 0; 
1996/0217    
		if(lenp) 
			*lenp = Dlen; 
1996/0201    
		break; 
	case Tagend: 
		x = GETS(md->bno); 
1996/0217    
		if(x > Dlen) 
1996/0201    
			return 0; 
1996/0217    
		if(lenp) 
			*lenp = x; 
1996/0201    
		break; 
1999/0612    
	default: 
		return 0; 
1996/0201    
	} 
	return md; 
} 
 
1996/0206    
static Mdata* 
1996/0217    
readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp) 
1996/0206    
{ 
	if(bno >= fs->nblocks) 
		return 0; 
1997/0327    
	if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) 
1996/0218    
		error(Eio); 
1996/0217    
	return validdata(fs, buf, lenp); 
1996/0206    
} 
 
1996/0218    
static void 
writedata(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); 
	 
1997/0327    
	if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen) 
1996/0218    
		error(Eio); 
} 
 
static void 
1996/0202    
writedir(Tfs *fs, Tfile *f) 
{ 
	Mdir *md; 
	uchar buf[Blen]; 
 
	if(f->bno == Notabno) 
1996/0218    
		return; 
1996/0202    
 
	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); 
1996/0218    
	md->sum = 0 - checksum(buf); 
1999/0612    
	 
1997/0327    
	if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) 
1996/0218    
		error(Eio); 
1996/0202    
} 
 
1996/0201    
static void 
1996/0220    
freeblocks(Tfs *fs, ulong bno, ulong bend) 
1996/0201    
{ 
	uchar buf[Blen]; 
	Mdata *md; 
 
1996/0220    
	if(waserror()) 
		return; 
 
1996/0202    
	while(bno != bend && bno != Notabno){ 
1996/0201    
		mapclr(fs, bno); 
1997/0327    
		if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) 
1996/0201    
			break; 
1996/0217    
		md = validdata(fs, buf, 0); 
1996/0201    
		if(md == 0) 
			break; 
		if(md->type == Tagend) 
			break; 
		bno = GETS(md->bno); 
	} 
 
1996/0220    
	poperror(); 
} 
 
static void 
freefile(Tfs *fs, Tfile *f, ulong bend) 
{ 
	uchar buf[Blen]; 
 
	/* remove blocks from map */ 
	freeblocks(fs, f->dbno, bend); 
 
1996/0201    
	/* change file type to free on medium */ 
1996/0202    
	if(f->bno != Notabno){ 
1999/0612    
		memset(buf, 0x55, Blen); 
1997/0327    
		devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); 
1996/0220    
		mapclr(fs, f->bno); 
1996/0202    
	} 
1996/0201    
 
	/* forget we ever knew about it */ 
	memset(f, 0, sizeof(*f)); 
} 
 
static void 
expand(Tfs *fs) 
{ 
	Tfile *f; 
 
	fs->fsize += 8; 
1999/0612    
	f = malloc(fs->fsize*sizeof(*f)); 
1996/0201    
 
1996/0220    
	if(fs->f){ 
		memmove(f, fs->f, fs->nf*sizeof(*f)); 
		free(fs->f); 
	} 
1996/0201    
	fs->f = f; 
} 
 
1996/0202    
static Tfile* 
newfile(Tfs *fs, char *name) 
{ 
	int i; 
1999/0612    
	volatile struct { 
		Tfile *f; 
		Tfs *fs; 
	} rock; 
1996/0202    
 
	/* find free entry in file table */ 
1999/0612    
	rock.f = 0; 
	rock.fs = fs; 
1996/0202    
	for(;;) { 
1999/0612    
		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); 
1996/0202    
				break; 
			} 
		} 
 
1999/0612    
		if(i < rock.fs->fsize){ 
			if(i >= rock.fs->nf) 
				rock.fs->nf = i+1; 
1996/0202    
			break; 
1996/0220    
		} 
1996/0202    
 
1999/0612    
		expand(rock.fs); 
1996/0202    
	} 
 
1999/0612    
	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?? 
1996/0202    
 
	/* write directory block */ 
	if(waserror()){ 
1999/0612    
		freefile(rock.fs, rock.f, Notabno); 
1996/0202    
		nexterror(); 
	} 
1999/0612    
	if(rock.f->bno == Notabno) 
1996/0202    
		error("out of space"); 
1999/0612    
	writedir(rock.fs, rock.f); 
1996/0202    
	poperror(); 
	 
1999/0612    
	return rock.f; 
1996/0202    
} 
 
1996/0123    
/* 
1996/0202    
 *  Read the whole medium and build a file table and used 
1996/0217    
 *  block bitmap.  Inconsistent files are purged.  The medium 
 *  had better be small or this could take a while. 
1996/0123    
 */ 
1996/0201    
static void 
1999/0612    
tfsinit(Tfs *fs) 
1996/0123    
{ 
1996/0218    
	char dbuf[DIRLEN]; 
1996/0123    
	Dir d; 
1996/0218    
	uchar buf[Blen]; 
1996/0131    
	ulong x, bno; 
1996/0217    
	int n, done; 
1996/0201    
	Tfile *f; 
	Mdir *mdir; 
1996/0218    
	Mdata *mdata; 
1996/0123    
 
1997/0327    
	devtab[fs->c->type]->stat(fs->c, dbuf); 
1996/0218    
	convM2D(dbuf, &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; 
1999/0612    
	fs->map = malloc(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++){ 
1997/0327    
		n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); 
1996/0131    
		if(n != Blen) 
			break; 
1996/0201    
 
1996/0218    
		mdir = validdir(fs, buf); 
1996/0201    
		if(mdir == 0) 
1996/0131    
			continue; 
1996/0201    
 
1996/0218    
		if(fs->nf >= fs->fsize) 
1996/0201    
			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; 
1999/0612    
		f->fbno = Notabno; 
1996/0201    
	} 
 
	/* follow files */ 
1996/0217    
	for(f = fs->f; f < &(fs->f[fs->nf]); f++){ 
1996/0218    
		bno = f->dbno; 
1996/0217    
		for(done = 0; !done;) { 
1996/0201    
			if(isalloced(fs, bno)){ 
1996/0218    
				freefile(fs, f, bno); 
1996/0201    
				break; 
			} 
1997/0327    
			n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); 
1996/0201    
			if(n != Blen){ 
				freefile(fs, f, bno); 
				break; 
			} 
1996/0217    
			mdata = validdata(fs, buf, 0); 
1996/0201    
			if(mdata == 0){ 
				freefile(fs, f, bno); 
				break; 
			} 
1996/0131    
			mapset(fs, bno); 
1996/0201    
			switch(mdata->type){ 
			case Tagdata: 
				bno = GETS(mdata->bno); 
1996/0218    
				f->length += Dlen; 
1996/0201    
				break; 
			case Tagend: 
1996/0218    
				f->length += GETS(mdata->bno); 
1996/0217    
				done = 1; 
1996/0201    
				break; 
			} 
1996/0217    
			if(done) 
				f->flag &= ~Fcreating; 
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    
 
1999/0612    
	USED(ntab); 
	USED(tab); 
1996/0218    
 
1996/0201    
	fs = &tinyfs.fs[c->dev]; 
	if(i >= fs->nf) 
		return -1; 
	f = &fs->f[i]; 
1996/0220    
	if(f->name[0] == 0) 
		return 0; 
1996/0201    
	qid.path = i; 
	qid.vers = 0; 
1999/0618    
	devdir(c, qid, f->name, f->length, eve, 0775, dp); 
1996/0201    
	return 1; 
1996/0123    
} 
 
1997/0327    
static void 
1999/0612    
tinyfsinit(void) 
1996/0201    
{ 
	if(Nlen > NAMELEN) 
1999/0612    
		panic("tinyfsinit"); 
1996/0201    
} 
 
1999/0612    
/* 
 *  specifier is an open file descriptor 
 */ 
1997/0327    
static Chan* 
1999/0623    
tinyfsattach(char *spec) 
1996/0116    
{ 
1996/0201    
	Tfs *fs; 
1999/0612    
	Chan *c; 
	volatile struct { Chan *cc; } rock; 
1999/0618    
	int i; 
	char buf[NAMELEN*2]; 
1996/0120    
 
1999/0618    
	snprint(buf, sizeof(buf), "/dev/%s", spec); 
	rock.cc = namec(buf, Aopen, ORDWR, 0); 
1996/0220    
 
1996/0123    
	if(waserror()){ 
1999/0612    
		cclose(rock.cc); 
1996/0123    
		nexterror(); 
	} 
1996/0201    
 
1996/0218    
	fs = 0; 
1996/0220    
	for(i = 0; i < Maxfs; i++){ 
1996/0201    
		fs = &tinyfs.fs[i]; 
1996/0226    
		qlock(&fs->ql); 
1999/0612    
		if(fs->r && eqchan(rock.cc, fs->c, 1)) 
1996/0122    
			break; 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1996/0220    
	if(i < Maxfs){ 
1996/0201    
		fs->r++; 
1996/0226    
		qunlock(&fs->ql); 
1999/0612    
		cclose(rock.cc); 
1996/0122    
	} else { 
1996/0220    
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ 
1996/0226    
			qlock(&fs->ql); 
1996/0220    
			if(fs->r == 0) 
				break; 
1996/0226    
			qunlock(&fs->ql); 
1996/0220    
		} 
		if(fs == &tinyfs.fs[Maxfs]) 
1996/0201    
			error("too many tinyfs's"); 
1999/0612    
		fs->c = rock.cc; 
1996/0201    
		fs->r = 1; 
1996/0220    
		fs->f = 0; 
		fs->nf = 0; 
		fs->fsize = 0; 
1999/0612    
		tfsinit(fs); 
1996/0226    
		qunlock(&fs->ql); 
1996/0122    
	} 
1996/0123    
	poperror(); 
1996/0122    
 
1999/0612    
	c = devattach('F', spec); 
1996/0201    
	c->dev = fs - tinyfs.fs; 
	c->qid.path = CHDIR; 
	c->qid.vers = 0; 
1996/0122    
 
	return c; 
1996/0116    
} 
 
1997/0327    
static Chan* 
1996/0116    
tinyfsclone(Chan *c, Chan *nc) 
{ 
1996/0218    
	Tfs *fs; 
 
	fs = &tinyfs.fs[c->dev]; 
 
1996/0226    
	qlock(&fs->ql); 
1996/0202    
	fs->r++; 
1996/0226    
	qunlock(&fs->ql); 
1996/0202    
 
1996/0116    
	return devclone(c, nc); 
} 
 
1997/0327    
static int 
1996/0116    
tinyfswalk(Chan *c, char *name) 
{ 
1996/0202    
	int n; 
1996/0218    
	Tfs *fs; 
1996/0202    
 
1996/0218    
	fs = &tinyfs.fs[c->dev]; 
 
1996/0226    
	qlock(&fs->ql); 
1996/0202    
	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++; 
	} 
1996/0226    
	qunlock(&fs->ql); 
1996/0202    
	return n; 
1996/0116    
} 
 
1997/0327    
static void 
1996/0116    
tinyfsstat(Chan *c, char *db) 
{ 
1996/0201    
	devstat(c, db, 0, 0, tinyfsgen); 
1996/0116    
} 
 
1997/0327    
static Chan* 
1996/0116    
tinyfsopen(Chan *c, int omode) 
{ 
1996/0201    
	Tfile *f; 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1996/0218    
	if(c->qid.path & CHDIR){ 
1996/0201    
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
1999/0612    
		qlock(&rock.fs->ql); 
1996/0220    
		if(waserror()){ 
1999/0612    
			qunlock(&rock.fs->ql); 
1996/0220    
			nexterror(); 
		} 
		switch(omode){ 
		case OTRUNC|ORDWR: 
		case OTRUNC|OWRITE: 
1999/0612    
			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; 
1996/0220    
			break; 
		case OREAD: 
1999/0618    
		case OEXEC: 
1996/0220    
			break; 
		default: 
1996/0202    
			error(Eperm); 
1996/0201    
		} 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		poperror(); 
1996/0201    
	} 
 
	return devopen(c, omode, 0, 0, tinyfsgen); 
1996/0116    
} 
 
1997/0327    
static void 
1996/0116    
tinyfscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
	Tfile *f; 
1996/0116    
 
1996/0220    
	USED(perm); 
1996/0116    
 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0218    
 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0220    
	if(waserror()){ 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		nexterror(); 
	} 
1999/0612    
	f = newfile(rock.fs, name); 
	qunlock(&rock.fs->ql); 
1996/0220    
	poperror(); 
1996/0201    
 
1999/0612    
	c->qid.path = f - rock.fs->f; 
1996/0202    
	c->qid.vers = 0; 
1996/0116    
	c->mode = openmode(omode); 
} 
 
1997/0327    
static void 
1996/0116    
tinyfsremove(Chan *c) 
{ 
1996/0220    
	Tfs *fs; 
	Tfile *f; 
 
	if(c->qid.path == CHDIR) 
		error(Eperm); 
	fs = &tinyfs.fs[c->dev]; 
	f = &fs->f[c->qid.path]; 
1996/0226    
	qlock(&fs->ql); 
1996/0220    
	freefile(fs, f, Notabno); 
1996/0226    
	qunlock(&fs->ql); 
1996/0116    
} 
 
1997/0327    
static void 
1996/0116    
tinyfsclose(Chan *c) 
{ 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0201    
	Tfile *f, *nf; 
1996/0202    
	int i; 
1996/0201    
 
1999/0612    
	rock.fs = &tinyfs.fs[c->dev]; 
1996/0201    
 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0201    
 
1996/0202    
	/* dereference file and remove old versions */ 
1996/0220    
	if(!waserror()){ 
		if(c->qid.path != CHDIR){ 
1999/0612    
			f = &rock.fs->f[c->qid.path]; 
1996/0220    
			f->r--; 
			if(f->r == 0){ 
				if(f->flag & Frmonclose) 
1999/0612    
					freefile(rock.fs, f, Notabno); 
1996/0220    
				else if(f->flag & Fcreating){ 
					/* remove all other files with this name */ 
1999/0612    
					for(i = 0; i < rock.fs->fsize; i++){ 
						nf = &rock.fs->f[i]; 
1996/0220    
						if(f == nf) 
							continue; 
						if(strcmp(nf->name, f->name) == 0){ 
							if(nf->r) 
								nf->flag |= Frmonclose; 
							else 
1999/0612    
								freefile(rock.fs, nf, Notabno); 
1996/0220    
						} 
1996/0203    
					} 
1996/0220    
					f->flag &= ~Fcreating; 
1996/0203    
				} 
1996/0202    
			} 
		} 
1996/0220    
		poperror(); 
1996/0202    
	} 
 
1999/0612    
	/* 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; 
1996/0201    
	} 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0116    
} 
 
1997/0327    
static long 
1999/0612    
tinyfsread(Chan *c, void *a, long n, vlong offset) 
1996/0116    
{ 
1999/0612    
	volatile struct { Tfs *fs; } rock; 
1996/0203    
	Tfile *f; 
1996/0220    
	int sofar, i, off; 
1996/0218    
	ulong bno; 
1996/0206    
	Mdata *md; 
	uchar buf[Blen]; 
1999/0612    
	uchar *p; 
1996/0203    
 
	if(c->qid.path & CHDIR) 
1996/0217    
		return devdirread(c, a, n, 0, 0, tinyfsgen); 
1996/0203    
 
1999/0612    
	p = a; 
	rock.fs = &tinyfs.fs[c->dev]; 
	f = &rock.fs->f[c->qid.path]; 
1996/0203    
	if(offset >= f->length) 
		return 0; 
1996/0220    
 
1999/0612    
	qlock(&rock.fs->ql); 
1996/0220    
	if(waserror()){ 
1999/0612    
		qunlock(&rock.fs->ql); 
1996/0220    
		nexterror(); 
	} 
1996/0203    
	if(n + offset >= f->length) 
		n = f->length - offset; 
1996/0206    
 
1996/0217    
	/* walk to starting data block */ 
1999/0612    
	if(0 && f->finger <= offset && f->fbno != Notabno){ 
1996/0220    
		sofar = f->finger; 
		bno = f->fbno; 
	} else { 
		sofar = 0; 
		bno = f->dbno; 
	} 
1999/0612    
	for(; sofar + Dlen <= offset; sofar += Dlen){ 
		md = readdata(rock.fs, bno, buf, 0); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1996/0206    
		bno = GETS(md->bno); 
	} 
 
	/* read data */ 
1996/0220    
	off = offset%Dlen; 
	offset -= off; 
1996/0217    
	for(sofar = 0; sofar < n; sofar += i){ 
1999/0612    
		md = readdata(rock.fs, bno, buf, &i); 
1996/0220    
		if(md == 0) 
			error(Eio); 
 
		/* update finger for successful read */ 
1999/0612    
		f->finger = offset; 
1996/0220    
		f->fbno = bno; 
1999/0612    
		offset += Dlen; 
1996/0220    
 
		i -= off; 
1999/0612    
		if(i > n - sofar) 
			i = n - sofar; 
		memmove(p, md->data+off, i); 
1996/0217    
		p += i; 
		bno = GETS(md->bno); 
1996/0220    
		off = 0; 
1996/0217    
	} 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0220    
	poperror(); 
1996/0203    
 
1996/0217    
	return sofar; 
1996/0116    
} 
 
1996/0220    
/* 
 *  if we get a write error in this routine, blocks will 
 *  be lost.  They should be recovered next fsinit. 
 */ 
1997/0327    
static long 
1999/0612    
tinyfswrite(Chan *c, void *a, long n, vlong offset) 
1996/0116    
{ 
1996/0217    
	Tfile *f; 
1999/0612    
	int last, next, i, finger, off, used; 
	ulong bno, fbno; 
1996/0217    
	Mdata *md; 
	uchar buf[Blen]; 
1999/0612    
	uchar *p; 
	volatile struct { 
		Tfs *fs; 
		ulong dbno; 
	} rock; 
1996/0217    
 
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
1996/0218    
	if(n == 0) 
		return 0; 
 
1999/0612    
	p = a; 
	rock.fs = &tinyfs.fs[c->dev]; 
	f = &rock.fs->f[c->qid.path]; 
1996/0217    
 
1999/0612    
	qlock(&rock.fs->ql); 
	rock.dbno = Notabno; 
1996/0218    
	if(waserror()){ 
1999/0612    
		freeblocks(rock.fs, rock.dbno, Notabno); 
		qunlock(&rock.fs->ql); 
1996/0218    
		nexterror(); 
	} 
 
1999/0612    
	/* files are append only, anything else is illegal */ 
	if(offset != f->length) 
		error("append only"); 
 
1996/0220    
	/* write blocks backwards */ 
	p += n; 
	last = offset + n; 
	fbno = Notabno; 
	finger = 0; 
1999/0612    
	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) 
1996/0220    
			error("out of space"); 
		i = last - next; 
		p -= i; 
		if(last == n+offset){ 
1999/0612    
			writedata(rock.fs, bno, rock.dbno, p, i, 1); 
1996/0220    
			finger = next;	/* remember for later */ 
			fbno = bno; 
1999/0612    
		} else { 
			writedata(rock.fs, bno, rock.dbno, p, i, 0); 
		} 
		rock.dbno = bno; 
1996/0220    
		last = next; 
	} 
 
1996/0218    
	/* walk to last data block */ 
1996/0220    
	md = (Mdata*)buf; 
1999/0612    
	if(0 && f->finger < offset && f->fbno != Notabno){ 
1996/0220    
		next = f->finger; 
		bno = f->fbno; 
	} else { 
		next = 0; 
		bno = f->dbno; 
	} 
1999/0612    
 
	used = 0; 
	while(bno != Notabno){ 
		md = readdata(rock.fs, bno, buf, &used); 
1996/0220    
		if(md == 0) 
			error(Eio); 
1999/0612    
		if(md->type == Tagend){ 
			if(next + Dlen < offset) 
				panic("devtinyfs1"); 
1996/0218    
			break; 
1999/0612    
		} 
		next += Dlen; 
		if(next > offset) 
			panic("devtinyfs1"); 
1996/0217    
		bno = GETS(md->bno); 
1996/0116    
	} 
 
1996/0220    
	/* point to new blocks */ 
	if(offset == 0){ 
1999/0612    
		/* first block in a file */ 
		f->dbno = rock.dbno; 
		writedir(rock.fs, f); 
1996/0220    
	} else { 
1999/0612    
		/* updating a current block */ 
1996/0220    
		i = last - offset; 
		if(i > 0){ 
			p -= i; 
1999/0612    
			memmove(md->data + used, p, i); 
			used += i; 
1996/0218    
		} 
1999/0612    
		writedata(rock.fs, bno, rock.dbno, md->data, used, last == n+offset); 
1996/0218    
	} 
1996/0220    
	f->length += n; 
1996/0218    
 
1996/0220    
	/* update finger */ 
	if(fbno != Notabno){ 
		f->finger = finger; 
		f->fbno =  fbno; 
	} 
1996/0218    
	poperror(); 
1999/0612    
	qunlock(&rock.fs->ql); 
1996/0217    
 
1996/0220    
	return n; 
1996/0116    
} 
 
1997/0327    
Dev tinyfsdevtab = { 
1999/0612    
	'F', 
1997/0408    
	"tinyfs", 
 
1999/0612    
	devreset, 
	tinyfsinit, 
1997/0327    
	tinyfsattach, 
	tinyfsclone, 
	tinyfswalk, 
	tinyfsstat, 
	tinyfsopen, 
	tinyfscreate, 
	tinyfsclose, 
	tinyfsread, 
	devbread, 
	tinyfswrite, 
	devbwrite, 
	tinyfsremove, 
	devwstat, 
}; 


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