xref: /inferno-os/emu/port/devtinyfs.c (revision 67d4cb07c1a40a27872c4da282fbe1417aa87731)
137da2899SCharles.Forsyth #include	"dat.h"
237da2899SCharles.Forsyth #include	"fns.h"
337da2899SCharles.Forsyth #include	"error.h"
437da2899SCharles.Forsyth 
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth enum{
737da2899SCharles.Forsyth 	Qdir,
837da2899SCharles.Forsyth 	Qmedium,
937da2899SCharles.Forsyth 
1037da2899SCharles.Forsyth 	Maxfs=		10,	/* max file systems */
1137da2899SCharles.Forsyth 
1237da2899SCharles.Forsyth 	Blen=		48,	/* block length */
1337da2899SCharles.Forsyth 	Nlen=		28,	/* name length */
1437da2899SCharles.Forsyth 	Dlen=		Blen - 4,
1537da2899SCharles.Forsyth 
1637da2899SCharles.Forsyth 	Tagdir=		'd',
1737da2899SCharles.Forsyth 	Tagdata=	'D',
1837da2899SCharles.Forsyth 	Tagend=		'e',
1937da2899SCharles.Forsyth 	Tagfree=	'f',
2037da2899SCharles.Forsyth 
2137da2899SCharles.Forsyth 	Notapin=		0xffff,
2237da2899SCharles.Forsyth 	Notabno=		0xffff,
2337da2899SCharles.Forsyth 
2437da2899SCharles.Forsyth 	Fcreating=	1,
2537da2899SCharles.Forsyth 	Frmonclose=	2
2637da2899SCharles.Forsyth };
2737da2899SCharles.Forsyth 
2837da2899SCharles.Forsyth /* representation of a Tdir on medium */
2937da2899SCharles.Forsyth typedef struct Mdir Mdir;
3037da2899SCharles.Forsyth struct Mdir {
3137da2899SCharles.Forsyth 	uchar	type;
3237da2899SCharles.Forsyth 	uchar	bno[2];
3337da2899SCharles.Forsyth 	uchar	pin[2];
3437da2899SCharles.Forsyth 	char	name[Nlen];
3537da2899SCharles.Forsyth 	char	pad[Blen - Nlen - 6];
3637da2899SCharles.Forsyth 	uchar	sum;
3737da2899SCharles.Forsyth };
3837da2899SCharles.Forsyth 
3937da2899SCharles.Forsyth /* representation of a Tdata/Tend on medium */
4037da2899SCharles.Forsyth typedef struct Mdata Mdata;
4137da2899SCharles.Forsyth struct Mdata {
4237da2899SCharles.Forsyth 	uchar	type;
4337da2899SCharles.Forsyth 	uchar	bno[2];
4437da2899SCharles.Forsyth 	uchar	data[Dlen];
4537da2899SCharles.Forsyth 	uchar	sum;
4637da2899SCharles.Forsyth };
4737da2899SCharles.Forsyth 
4837da2899SCharles.Forsyth typedef struct Tfile Tfile;
4937da2899SCharles.Forsyth struct Tfile {
5037da2899SCharles.Forsyth 	int	r;
5137da2899SCharles.Forsyth 	char	name[Nlen];
5237da2899SCharles.Forsyth 	ushort	bno;
5337da2899SCharles.Forsyth 	ushort	dbno;
5437da2899SCharles.Forsyth 	ushort	pin;
5537da2899SCharles.Forsyth 	uchar	flag;
5637da2899SCharles.Forsyth 	ulong	length;
5737da2899SCharles.Forsyth 
5837da2899SCharles.Forsyth 	/* hint to avoid egregious reading */
5937da2899SCharles.Forsyth 	ushort	fbno;
6037da2899SCharles.Forsyth 	ulong	finger;
6137da2899SCharles.Forsyth };
6237da2899SCharles.Forsyth 
6337da2899SCharles.Forsyth typedef struct Tfs Tfs;
6437da2899SCharles.Forsyth struct Tfs {
6537da2899SCharles.Forsyth 	QLock	ql;
6637da2899SCharles.Forsyth 	int	r;
6737da2899SCharles.Forsyth 	Chan	*c;
6837da2899SCharles.Forsyth 	uchar	*map;
6937da2899SCharles.Forsyth 	int	nblocks;
7037da2899SCharles.Forsyth 	Tfile	*f;
7137da2899SCharles.Forsyth 	int	nf;
7237da2899SCharles.Forsyth 	int	fsize;
7337da2899SCharles.Forsyth };
7437da2899SCharles.Forsyth 
7537da2899SCharles.Forsyth static struct {
7637da2899SCharles.Forsyth 	Tfs	fs[Maxfs];
7737da2899SCharles.Forsyth } tinyfs;
7837da2899SCharles.Forsyth 
7937da2899SCharles.Forsyth #define GETS(x) ((x)[0]|((x)[1]<<8))
8037da2899SCharles.Forsyth #define PUTS(x, v) {(x)[0] = (v);(x)[1] = ((v)>>8);}
8137da2899SCharles.Forsyth 
8237da2899SCharles.Forsyth #define GETL(x) (GETS(x)|(GETS(x+2)<<16))
8337da2899SCharles.Forsyth #define PUTL(x, v) {PUTS(x, v);PUTS(x+2, (v)>>16)};
8437da2899SCharles.Forsyth 
8537da2899SCharles.Forsyth static uchar
checksum(uchar * p)8637da2899SCharles.Forsyth checksum(uchar *p)
8737da2899SCharles.Forsyth {
8837da2899SCharles.Forsyth 	uchar *e;
8937da2899SCharles.Forsyth 	uchar s;
9037da2899SCharles.Forsyth 
9137da2899SCharles.Forsyth 	s = 0;
9237da2899SCharles.Forsyth 	for(e = p + Blen; p < e; p++)
9337da2899SCharles.Forsyth 		s += *p;
9437da2899SCharles.Forsyth 	return s;
9537da2899SCharles.Forsyth }
9637da2899SCharles.Forsyth 
9737da2899SCharles.Forsyth static void
mapclr(Tfs * fs,ulong bno)9837da2899SCharles.Forsyth mapclr(Tfs *fs, ulong bno)
9937da2899SCharles.Forsyth {
10037da2899SCharles.Forsyth 	fs->map[bno>>3] &= ~(1<<(bno&7));
10137da2899SCharles.Forsyth }
10237da2899SCharles.Forsyth 
10337da2899SCharles.Forsyth static void
mapset(Tfs * fs,ulong bno)10437da2899SCharles.Forsyth mapset(Tfs *fs, ulong bno)
10537da2899SCharles.Forsyth {
10637da2899SCharles.Forsyth 	fs->map[bno>>3] |= 1<<(bno&7);
10737da2899SCharles.Forsyth }
10837da2899SCharles.Forsyth 
10937da2899SCharles.Forsyth static int
isalloced(Tfs * fs,ulong bno)11037da2899SCharles.Forsyth isalloced(Tfs *fs, ulong bno)
11137da2899SCharles.Forsyth {
11237da2899SCharles.Forsyth 	return fs->map[bno>>3] & (1<<(bno&7));
11337da2899SCharles.Forsyth }
11437da2899SCharles.Forsyth 
11537da2899SCharles.Forsyth static int
mapalloc(Tfs * fs)11637da2899SCharles.Forsyth mapalloc(Tfs *fs)
11737da2899SCharles.Forsyth {
11837da2899SCharles.Forsyth 	int i, j, lim;
11937da2899SCharles.Forsyth 	uchar x;
12037da2899SCharles.Forsyth 
12137da2899SCharles.Forsyth 	lim = (fs->nblocks + 8 - 1)/8;
12237da2899SCharles.Forsyth 	for(i = 0; i < lim; i++){
12337da2899SCharles.Forsyth 		x = fs->map[i];
12437da2899SCharles.Forsyth 		if(x == 0xff)
12537da2899SCharles.Forsyth 			continue;
12637da2899SCharles.Forsyth 		for(j = 0; j < 8; j++)
12737da2899SCharles.Forsyth 			if((x & (1<<j)) == 0){
12837da2899SCharles.Forsyth 				fs->map[i] = x|(1<<j);
12937da2899SCharles.Forsyth 				return i*8 + j;
13037da2899SCharles.Forsyth 			}
13137da2899SCharles.Forsyth 	}
13237da2899SCharles.Forsyth 
13337da2899SCharles.Forsyth 	return Notabno;
13437da2899SCharles.Forsyth }
13537da2899SCharles.Forsyth 
13637da2899SCharles.Forsyth static Mdir*
validdir(Tfs * fs,uchar * p)13737da2899SCharles.Forsyth validdir(Tfs *fs, uchar *p)
13837da2899SCharles.Forsyth {
13937da2899SCharles.Forsyth 	Mdir *md;
14037da2899SCharles.Forsyth 	ulong x;
14137da2899SCharles.Forsyth 
14237da2899SCharles.Forsyth 	if(checksum(p) != 0)
14337da2899SCharles.Forsyth 		return 0;
14437da2899SCharles.Forsyth 	if(p[0] != Tagdir)
14537da2899SCharles.Forsyth 		return 0;
14637da2899SCharles.Forsyth 	md = (Mdir*)p;
14737da2899SCharles.Forsyth 	x = GETS(md->bno);
14837da2899SCharles.Forsyth 	if(x >= fs->nblocks)
14937da2899SCharles.Forsyth 		return 0;
15037da2899SCharles.Forsyth 	return md;
15137da2899SCharles.Forsyth }
15237da2899SCharles.Forsyth 
15337da2899SCharles.Forsyth static Mdata*
validdata(Tfs * fs,uchar * p,int * lenp)15437da2899SCharles.Forsyth validdata(Tfs *fs, uchar *p, int *lenp)
15537da2899SCharles.Forsyth {
15637da2899SCharles.Forsyth 	Mdata *md;
15737da2899SCharles.Forsyth 	ulong x;
15837da2899SCharles.Forsyth 
15937da2899SCharles.Forsyth 	if(checksum(p) != 0)
16037da2899SCharles.Forsyth 		return 0;
16137da2899SCharles.Forsyth 	md = (Mdata*)p;
16237da2899SCharles.Forsyth 	switch(md->type){
16337da2899SCharles.Forsyth 	case Tagdata:
16437da2899SCharles.Forsyth 		x = GETS(md->bno);
16537da2899SCharles.Forsyth 		if(x >= fs->nblocks)
16637da2899SCharles.Forsyth 			return 0;
16737da2899SCharles.Forsyth 		if(lenp)
16837da2899SCharles.Forsyth 			*lenp = Dlen;
16937da2899SCharles.Forsyth 		break;
17037da2899SCharles.Forsyth 	case Tagend:
17137da2899SCharles.Forsyth 		x = GETS(md->bno);
17237da2899SCharles.Forsyth 		if(x > Dlen)
17337da2899SCharles.Forsyth 			return 0;
17437da2899SCharles.Forsyth 		if(lenp)
17537da2899SCharles.Forsyth 			*lenp = x;
17637da2899SCharles.Forsyth 		break;
17737da2899SCharles.Forsyth 	default:
17837da2899SCharles.Forsyth 		return 0;
17937da2899SCharles.Forsyth 	}
18037da2899SCharles.Forsyth 	return md;
18137da2899SCharles.Forsyth }
18237da2899SCharles.Forsyth 
18337da2899SCharles.Forsyth static Mdata*
readdata(Tfs * fs,ulong bno,uchar * buf,int * lenp)18437da2899SCharles.Forsyth readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp)
18537da2899SCharles.Forsyth {
18637da2899SCharles.Forsyth 	if(bno >= fs->nblocks)
18737da2899SCharles.Forsyth 		return 0;
188*67d4cb07Sforsyth 	if(fs->c->dev->read(fs->c, buf, Blen, Blen*bno) != Blen)
18937da2899SCharles.Forsyth 		error(Eio);
19037da2899SCharles.Forsyth 	return validdata(fs, buf, lenp);
19137da2899SCharles.Forsyth }
19237da2899SCharles.Forsyth 
19337da2899SCharles.Forsyth static void
writedata(Tfs * fs,ulong bno,ulong next,uchar * buf,int len,int last)19437da2899SCharles.Forsyth writedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last)
19537da2899SCharles.Forsyth {
19637da2899SCharles.Forsyth 	Mdata md;
19737da2899SCharles.Forsyth 
19837da2899SCharles.Forsyth 	if(bno >= fs->nblocks)
19937da2899SCharles.Forsyth 		error(Eio);
20037da2899SCharles.Forsyth 	if(len > Dlen)
20137da2899SCharles.Forsyth 		len = Dlen;
20237da2899SCharles.Forsyth 	if(len < 0)
20337da2899SCharles.Forsyth 		error(Eio);
20437da2899SCharles.Forsyth 	memset(&md, 0, sizeof(md));
20537da2899SCharles.Forsyth 	if(last){
20637da2899SCharles.Forsyth 		md.type = Tagend;
20737da2899SCharles.Forsyth 		PUTS(md.bno, len);
20837da2899SCharles.Forsyth 	} else {
20937da2899SCharles.Forsyth 		md.type = Tagdata;
21037da2899SCharles.Forsyth 		PUTS(md.bno, next);
21137da2899SCharles.Forsyth 	}
21237da2899SCharles.Forsyth 	memmove(md.data, buf, len);
21337da2899SCharles.Forsyth 	md.sum = 0 - checksum((uchar*)&md);
21437da2899SCharles.Forsyth 
215*67d4cb07Sforsyth 	if(fs->c->dev->write(fs->c, &md, Blen, Blen*bno) != Blen)
21637da2899SCharles.Forsyth 		error(Eio);
21737da2899SCharles.Forsyth }
21837da2899SCharles.Forsyth 
21937da2899SCharles.Forsyth static void
writedir(Tfs * fs,Tfile * f)22037da2899SCharles.Forsyth writedir(Tfs *fs, Tfile *f)
22137da2899SCharles.Forsyth {
22237da2899SCharles.Forsyth 	Mdir *md;
22337da2899SCharles.Forsyth 	uchar buf[Blen];
22437da2899SCharles.Forsyth 
22537da2899SCharles.Forsyth 	if(f->bno == Notabno)
22637da2899SCharles.Forsyth 		return;
22737da2899SCharles.Forsyth 
22837da2899SCharles.Forsyth 	md = (Mdir*)buf;
22937da2899SCharles.Forsyth 	memset(buf, 0, Blen);
23037da2899SCharles.Forsyth 	md->type = Tagdir;
23137da2899SCharles.Forsyth 	strncpy(md->name, f->name, sizeof(md->name)-1);
23237da2899SCharles.Forsyth 	PUTS(md->bno, f->dbno);
23337da2899SCharles.Forsyth 	PUTS(md->pin, f->pin);
23437da2899SCharles.Forsyth 	md->sum = 0 - checksum(buf);
23537da2899SCharles.Forsyth 
236*67d4cb07Sforsyth 	if(fs->c->dev->write(fs->c, buf, Blen, Blen*f->bno) != Blen)
23737da2899SCharles.Forsyth 		error(Eio);
23837da2899SCharles.Forsyth }
23937da2899SCharles.Forsyth 
24037da2899SCharles.Forsyth static void
freeblocks(Tfs * fs,ulong bno,ulong bend)24137da2899SCharles.Forsyth freeblocks(Tfs *fs, ulong bno, ulong bend)
24237da2899SCharles.Forsyth {
24337da2899SCharles.Forsyth 	uchar buf[Blen];
24437da2899SCharles.Forsyth 	Mdata *md;
24537da2899SCharles.Forsyth 
24637da2899SCharles.Forsyth 	if(waserror())
24737da2899SCharles.Forsyth 		return;
24837da2899SCharles.Forsyth 
24937da2899SCharles.Forsyth 	while(bno != bend && bno != Notabno){
25037da2899SCharles.Forsyth 		mapclr(fs, bno);
251*67d4cb07Sforsyth 		if(fs->c->dev->read(fs->c, buf, Blen, Blen*bno) != Blen)
25237da2899SCharles.Forsyth 			break;
25337da2899SCharles.Forsyth 		md = validdata(fs, buf, 0);
25437da2899SCharles.Forsyth 		if(md == 0)
25537da2899SCharles.Forsyth 			break;
25637da2899SCharles.Forsyth 		if(md->type == Tagend)
25737da2899SCharles.Forsyth 			break;
25837da2899SCharles.Forsyth 		bno = GETS(md->bno);
25937da2899SCharles.Forsyth 	}
26037da2899SCharles.Forsyth 
26137da2899SCharles.Forsyth 	poperror();
26237da2899SCharles.Forsyth }
26337da2899SCharles.Forsyth 
26437da2899SCharles.Forsyth static void
freefile(Tfs * fs,Tfile * f,ulong bend)26537da2899SCharles.Forsyth freefile(Tfs *fs, Tfile *f, ulong bend)
26637da2899SCharles.Forsyth {
26737da2899SCharles.Forsyth 	uchar buf[Blen];
26837da2899SCharles.Forsyth 
26937da2899SCharles.Forsyth 	/* remove blocks from map */
27037da2899SCharles.Forsyth 	freeblocks(fs, f->dbno, bend);
27137da2899SCharles.Forsyth 
27237da2899SCharles.Forsyth 	/* change file type to free on medium */
27337da2899SCharles.Forsyth 	if(f->bno != Notabno){
27437da2899SCharles.Forsyth 		memset(buf, 0x55, Blen);
275*67d4cb07Sforsyth 		fs->c->dev->write(fs->c, buf, Blen, Blen*f->bno);
27637da2899SCharles.Forsyth 		mapclr(fs, f->bno);
27737da2899SCharles.Forsyth 	}
27837da2899SCharles.Forsyth 
27937da2899SCharles.Forsyth 	/* forget we ever knew about it */
28037da2899SCharles.Forsyth 	memset(f, 0, sizeof(*f));
28137da2899SCharles.Forsyth }
28237da2899SCharles.Forsyth 
28337da2899SCharles.Forsyth static void
expand(Tfs * fs)28437da2899SCharles.Forsyth expand(Tfs *fs)
28537da2899SCharles.Forsyth {
28637da2899SCharles.Forsyth 	Tfile *f;
28737da2899SCharles.Forsyth 
28837da2899SCharles.Forsyth 	fs->fsize += 8;
28937da2899SCharles.Forsyth 	f = malloc(fs->fsize*sizeof(*f));
29037da2899SCharles.Forsyth 	if(f == nil)
29137da2899SCharles.Forsyth 		error(Enomem);
29237da2899SCharles.Forsyth 
29337da2899SCharles.Forsyth 	if(fs->f){
29437da2899SCharles.Forsyth 		memmove(f, fs->f, fs->nf*sizeof(*f));
29537da2899SCharles.Forsyth 		free(fs->f);
29637da2899SCharles.Forsyth 	}
29737da2899SCharles.Forsyth 	fs->f = f;
29837da2899SCharles.Forsyth }
29937da2899SCharles.Forsyth 
30037da2899SCharles.Forsyth static Tfile*
newfile(Tfs * fs,char * name)30137da2899SCharles.Forsyth newfile(Tfs *fs, char *name)
30237da2899SCharles.Forsyth {
30337da2899SCharles.Forsyth 	int i;
30437da2899SCharles.Forsyth 	volatile struct {
30537da2899SCharles.Forsyth 		Tfile *f;
30637da2899SCharles.Forsyth 		Tfs *fs;
30737da2899SCharles.Forsyth 	} rock;
30837da2899SCharles.Forsyth 
30937da2899SCharles.Forsyth 	/* find free entry in file table */
31037da2899SCharles.Forsyth 	rock.f = 0;
31137da2899SCharles.Forsyth 	rock.fs = fs;
31237da2899SCharles.Forsyth 	for(;;) {
31337da2899SCharles.Forsyth 		for(i = 0; i < rock.fs->fsize; i++){
31437da2899SCharles.Forsyth 			rock.f = &rock.fs->f[i];
31537da2899SCharles.Forsyth 			if(rock.f->name[0] == 0){
31637da2899SCharles.Forsyth 				strncpy(rock.f->name, name, sizeof(rock.f->name)-1);
31737da2899SCharles.Forsyth 				break;
31837da2899SCharles.Forsyth 			}
31937da2899SCharles.Forsyth 		}
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 		if(i < rock.fs->fsize){
32237da2899SCharles.Forsyth 			if(i >= rock.fs->nf)
32337da2899SCharles.Forsyth 				rock.fs->nf = i+1;
32437da2899SCharles.Forsyth 			break;
32537da2899SCharles.Forsyth 		}
32637da2899SCharles.Forsyth 
32737da2899SCharles.Forsyth 		expand(rock.fs);
32837da2899SCharles.Forsyth 	}
32937da2899SCharles.Forsyth 
33037da2899SCharles.Forsyth 	rock.f->flag = Fcreating;
33137da2899SCharles.Forsyth 	rock.f->dbno = Notabno;
33237da2899SCharles.Forsyth 	rock.f->bno = mapalloc(rock.fs);
33337da2899SCharles.Forsyth 	rock.f->fbno = Notabno;
33437da2899SCharles.Forsyth 	rock.f->r = 1;
335*67d4cb07Sforsyth 	rock.f->pin = Notapin;
33637da2899SCharles.Forsyth 
33737da2899SCharles.Forsyth 	/* write directory block */
33837da2899SCharles.Forsyth 	if(waserror()){
33937da2899SCharles.Forsyth 		freefile(rock.fs, rock.f, Notabno);
34037da2899SCharles.Forsyth 		nexterror();
34137da2899SCharles.Forsyth 	}
34237da2899SCharles.Forsyth 	if(rock.f->bno == Notabno)
34337da2899SCharles.Forsyth 		error("out of space");
34437da2899SCharles.Forsyth 	writedir(rock.fs, rock.f);
34537da2899SCharles.Forsyth 	poperror();
34637da2899SCharles.Forsyth 
34737da2899SCharles.Forsyth 	return rock.f;
34837da2899SCharles.Forsyth }
34937da2899SCharles.Forsyth 
35037da2899SCharles.Forsyth /*
35137da2899SCharles.Forsyth  *  Read the whole medium and build a file table and used
35237da2899SCharles.Forsyth  *  block bitmap.  Inconsistent files are purged.  The medium
35337da2899SCharles.Forsyth  *  had better be small or this could take a while.
35437da2899SCharles.Forsyth  */
35537da2899SCharles.Forsyth static void
tfsinit(Tfs * fs)35637da2899SCharles.Forsyth tfsinit(Tfs *fs)
35737da2899SCharles.Forsyth {
35837da2899SCharles.Forsyth 	uchar dbuf[STATFIXLEN+32*4];
35937da2899SCharles.Forsyth 	Dir d;
36037da2899SCharles.Forsyth 	uchar buf[Blen];
36137da2899SCharles.Forsyth 	ulong x, bno;
36237da2899SCharles.Forsyth 	int n, done;
36337da2899SCharles.Forsyth 	Tfile *f;
36437da2899SCharles.Forsyth 	Mdir *mdir;
36537da2899SCharles.Forsyth 	Mdata *mdata;
36637da2899SCharles.Forsyth 
367*67d4cb07Sforsyth 	n = fs->c->dev->stat(fs->c, dbuf, sizeof(dbuf));
36837da2899SCharles.Forsyth 	n = convM2D(dbuf, n, &d, nil);
36937da2899SCharles.Forsyth 	if(n <= 0)
37037da2899SCharles.Forsyth 		error("cannot stat tinyfs medium");
37137da2899SCharles.Forsyth 	fs->nblocks = d.length/Blen;
37237da2899SCharles.Forsyth 	if(fs->nblocks < 3)
37337da2899SCharles.Forsyth 		error("tinyfs medium too small");
37437da2899SCharles.Forsyth 
37537da2899SCharles.Forsyth 	/* bitmap for block usage */
37637da2899SCharles.Forsyth 	x = (fs->nblocks + 8 - 1)/8;
37737da2899SCharles.Forsyth 	fs->map = malloc(x);
37837da2899SCharles.Forsyth 	if(fs->map == nil)
37937da2899SCharles.Forsyth 		error(Enomem);
38037da2899SCharles.Forsyth 	for(bno = fs->nblocks; bno < x*8; bno++)
38137da2899SCharles.Forsyth 		mapset(fs, bno);
38237da2899SCharles.Forsyth 
38337da2899SCharles.Forsyth 	/* find files */
38437da2899SCharles.Forsyth 	for(bno = 0; bno < fs->nblocks; bno++){
385*67d4cb07Sforsyth 		n = fs->c->dev->read(fs->c, buf, Blen, Blen*bno);
38637da2899SCharles.Forsyth 		if(n != Blen)
38737da2899SCharles.Forsyth 			break;
38837da2899SCharles.Forsyth 
38937da2899SCharles.Forsyth 		mdir = validdir(fs, buf);
39037da2899SCharles.Forsyth 		if(mdir == 0)
39137da2899SCharles.Forsyth 			continue;
39237da2899SCharles.Forsyth 
39337da2899SCharles.Forsyth 		if(fs->nf >= fs->fsize)
39437da2899SCharles.Forsyth 			expand(fs);
39537da2899SCharles.Forsyth 
39637da2899SCharles.Forsyth 		f = &fs->f[fs->nf++];
39737da2899SCharles.Forsyth 
39837da2899SCharles.Forsyth 		x = GETS(mdir->bno);
39937da2899SCharles.Forsyth 		mapset(fs, bno);
40037da2899SCharles.Forsyth 		strncpy(f->name, mdir->name, sizeof(f->name));
40137da2899SCharles.Forsyth 		f->pin = GETS(mdir->pin);
40237da2899SCharles.Forsyth 		f->bno = bno;
40337da2899SCharles.Forsyth 		f->dbno = x;
40437da2899SCharles.Forsyth 		f->fbno = Notabno;
40537da2899SCharles.Forsyth 	}
40637da2899SCharles.Forsyth 
40737da2899SCharles.Forsyth 	/* follow files */
40837da2899SCharles.Forsyth 	for(f = fs->f; f < &(fs->f[fs->nf]); f++){
40937da2899SCharles.Forsyth 		bno = f->dbno;
41037da2899SCharles.Forsyth 		for(done = 0; !done;) {
41137da2899SCharles.Forsyth 			if(isalloced(fs, bno)){
41237da2899SCharles.Forsyth 				freefile(fs, f, bno);
41337da2899SCharles.Forsyth 				break;
41437da2899SCharles.Forsyth 			}
415*67d4cb07Sforsyth 			n = fs->c->dev->read(fs->c, buf, Blen, Blen*bno);
41637da2899SCharles.Forsyth 			if(n != Blen){
41737da2899SCharles.Forsyth 				freefile(fs, f, bno);
41837da2899SCharles.Forsyth 				break;
41937da2899SCharles.Forsyth 			}
42037da2899SCharles.Forsyth 			mdata = validdata(fs, buf, 0);
42137da2899SCharles.Forsyth 			if(mdata == 0){
42237da2899SCharles.Forsyth 				freefile(fs, f, bno);
42337da2899SCharles.Forsyth 				break;
42437da2899SCharles.Forsyth 			}
42537da2899SCharles.Forsyth 			mapset(fs, bno);
42637da2899SCharles.Forsyth 			switch(mdata->type){
42737da2899SCharles.Forsyth 			case Tagdata:
42837da2899SCharles.Forsyth 				bno = GETS(mdata->bno);
42937da2899SCharles.Forsyth 				f->length += Dlen;
43037da2899SCharles.Forsyth 				break;
43137da2899SCharles.Forsyth 			case Tagend:
43237da2899SCharles.Forsyth 				f->length += GETS(mdata->bno);
43337da2899SCharles.Forsyth 				done = 1;
43437da2899SCharles.Forsyth 				break;
43537da2899SCharles.Forsyth 			}
43637da2899SCharles.Forsyth 			if(done)
43737da2899SCharles.Forsyth 				f->flag &= ~Fcreating;
43837da2899SCharles.Forsyth 		}
43937da2899SCharles.Forsyth 	}
44037da2899SCharles.Forsyth }
44137da2899SCharles.Forsyth 
44237da2899SCharles.Forsyth /*
44337da2899SCharles.Forsyth  *  single directory
44437da2899SCharles.Forsyth  */
44537da2899SCharles.Forsyth static int
tinyfsgen(Chan * c,char * name,Dirtab * tab,int ntab,int i,Dir * dp)44637da2899SCharles.Forsyth tinyfsgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
44737da2899SCharles.Forsyth {
44837da2899SCharles.Forsyth 	Tfs *fs;
44937da2899SCharles.Forsyth 	Tfile *f;
45037da2899SCharles.Forsyth 	Qid qid;
45137da2899SCharles.Forsyth 
45237da2899SCharles.Forsyth 	USED(name);
45337da2899SCharles.Forsyth 	USED(ntab);
45437da2899SCharles.Forsyth 	USED(tab);
45537da2899SCharles.Forsyth 
456*67d4cb07Sforsyth 	fs = &tinyfs.fs[c->devno];
45737da2899SCharles.Forsyth 	if(i >= fs->nf)
45837da2899SCharles.Forsyth 		return -1;
45937da2899SCharles.Forsyth 	qid.vers = 0;
46037da2899SCharles.Forsyth 	if(i == DEVDOTDOT){
46137da2899SCharles.Forsyth 		qid.type = QTDIR;
46237da2899SCharles.Forsyth 		devdir(c, qid, ".", 0, eve, DMDIR|0555, dp);
46337da2899SCharles.Forsyth 		return 1;
46437da2899SCharles.Forsyth 	}
46537da2899SCharles.Forsyth 	f = &fs->f[i];
46637da2899SCharles.Forsyth 	if(f->name[0] == 0)
46737da2899SCharles.Forsyth 		return 0;
46837da2899SCharles.Forsyth 	qid.path = i+1;
46937da2899SCharles.Forsyth 	qid.type = QTFILE;
47037da2899SCharles.Forsyth 	devdir(c, qid, f->name, f->length, eve, 0664, dp);
47137da2899SCharles.Forsyth 	return 1;
47237da2899SCharles.Forsyth }
47337da2899SCharles.Forsyth 
47437da2899SCharles.Forsyth /*
47537da2899SCharles.Forsyth  *  specifier is the name of a device in /dev
47637da2899SCharles.Forsyth  */
47737da2899SCharles.Forsyth static Chan *
tinyfsattach(char * spec)47837da2899SCharles.Forsyth tinyfsattach(char *spec)
47937da2899SCharles.Forsyth {
48037da2899SCharles.Forsyth 	Tfs *fs;
48137da2899SCharles.Forsyth 	Chan *c;
48237da2899SCharles.Forsyth 	volatile struct { Chan *cc; } rock;
48337da2899SCharles.Forsyth 	int i;
48437da2899SCharles.Forsyth 	char buf[KNAMELEN*3];
48537da2899SCharles.Forsyth 
48637da2899SCharles.Forsyth 	if(*spec == 0 || strchr(spec, '/') != nil)
48737da2899SCharles.Forsyth 		error("bad specifier");
48837da2899SCharles.Forsyth 
48937da2899SCharles.Forsyth 	snprint(buf, sizeof(buf), "/dev/%s", spec);
49037da2899SCharles.Forsyth 	rock.cc = namec(buf, Aopen, ORDWR, 0);
49137da2899SCharles.Forsyth 	if(waserror()){
49237da2899SCharles.Forsyth 		cclose(rock.cc);
49337da2899SCharles.Forsyth 		nexterror();
49437da2899SCharles.Forsyth 	}
49537da2899SCharles.Forsyth 
49637da2899SCharles.Forsyth 	fs = 0;
49737da2899SCharles.Forsyth 	for(i = 0; i < Maxfs; i++){
49837da2899SCharles.Forsyth 		fs = &tinyfs.fs[i];
49937da2899SCharles.Forsyth 		qlock(&fs->ql);
50037da2899SCharles.Forsyth 		if(fs->r && eqchan(rock.cc, fs->c, 1))
50137da2899SCharles.Forsyth 			break;
50237da2899SCharles.Forsyth 		qunlock(&fs->ql);
50337da2899SCharles.Forsyth 	}
50437da2899SCharles.Forsyth 	if(i < Maxfs){
50537da2899SCharles.Forsyth 		fs->r++;
50637da2899SCharles.Forsyth 		qunlock(&fs->ql);
50737da2899SCharles.Forsyth 		cclose(rock.cc);
50837da2899SCharles.Forsyth 	} else {
50937da2899SCharles.Forsyth 		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){
51037da2899SCharles.Forsyth 			qlock(&fs->ql);
51137da2899SCharles.Forsyth 			if(fs->r == 0)
51237da2899SCharles.Forsyth 				break;
51337da2899SCharles.Forsyth 			qunlock(&fs->ql);
51437da2899SCharles.Forsyth 		}
51537da2899SCharles.Forsyth 		if(fs == &tinyfs.fs[Maxfs])
51637da2899SCharles.Forsyth 			error("too many tinyfs's");
51737da2899SCharles.Forsyth 		fs->c = rock.cc;
51837da2899SCharles.Forsyth 		fs->r = 1;
51937da2899SCharles.Forsyth 		fs->f = 0;
52037da2899SCharles.Forsyth 		fs->nf = 0;
52137da2899SCharles.Forsyth 		fs->fsize = 0;
52237da2899SCharles.Forsyth 		tfsinit(fs);
52337da2899SCharles.Forsyth 		qunlock(&fs->ql);
52437da2899SCharles.Forsyth 	}
52537da2899SCharles.Forsyth 	poperror();
52637da2899SCharles.Forsyth 
52737da2899SCharles.Forsyth 	c = devattach('F', spec);
528*67d4cb07Sforsyth 	c->devno = fs - tinyfs.fs;
52937da2899SCharles.Forsyth 	c->qid.type = QTDIR;
53037da2899SCharles.Forsyth 	c->qid.vers = 0;
53137da2899SCharles.Forsyth 
53237da2899SCharles.Forsyth 	return c;
53337da2899SCharles.Forsyth }
53437da2899SCharles.Forsyth 
53537da2899SCharles.Forsyth static Walkqid*
tinyfswalk(Chan * c,Chan * nc,char ** name,int nname)53637da2899SCharles.Forsyth tinyfswalk(Chan *c, Chan *nc, char **name, int nname)
53737da2899SCharles.Forsyth {
53837da2899SCharles.Forsyth 	Tfs *fs;
53937da2899SCharles.Forsyth 	Walkqid *wq;
54037da2899SCharles.Forsyth 
541*67d4cb07Sforsyth 	fs = &tinyfs.fs[c->devno];
54237da2899SCharles.Forsyth 
54337da2899SCharles.Forsyth 	qlock(&fs->ql);
54437da2899SCharles.Forsyth 	wq = devwalk(c, nc, name, nname, 0, 0, tinyfsgen);
54537da2899SCharles.Forsyth 	if(wq != nil && (nc = wq->clone) != nil && nc->qid.path != Qdir){
546*67d4cb07Sforsyth 		fs = &tinyfs.fs[nc->devno];
54737da2899SCharles.Forsyth 		fs->f[nc->qid.path-1].r++;
54837da2899SCharles.Forsyth 	}
54937da2899SCharles.Forsyth 	qunlock(&fs->ql);
55037da2899SCharles.Forsyth 	return wq;
55137da2899SCharles.Forsyth }
55237da2899SCharles.Forsyth 
55337da2899SCharles.Forsyth static int
tinyfsstat(Chan * c,uchar * db,int n)55437da2899SCharles.Forsyth tinyfsstat(Chan *c, uchar *db, int n)
55537da2899SCharles.Forsyth {
55637da2899SCharles.Forsyth 	return devstat(c, db, n, 0, 0, tinyfsgen);
55737da2899SCharles.Forsyth }
55837da2899SCharles.Forsyth 
55937da2899SCharles.Forsyth static Chan *
tinyfsopen(Chan * c,int omode)56037da2899SCharles.Forsyth tinyfsopen(Chan *c, int omode)
56137da2899SCharles.Forsyth {
56237da2899SCharles.Forsyth 	Tfile *f;
56337da2899SCharles.Forsyth 	volatile struct { Tfs *fs; } rock;
56437da2899SCharles.Forsyth 
565*67d4cb07Sforsyth 	rock.fs = &tinyfs.fs[c->devno];
56637da2899SCharles.Forsyth 
56737da2899SCharles.Forsyth 	if(c->qid.type & QTDIR){
56837da2899SCharles.Forsyth 		if(omode != OREAD)
56937da2899SCharles.Forsyth 			error(Eperm);
57037da2899SCharles.Forsyth 	} else {
57137da2899SCharles.Forsyth 		qlock(&rock.fs->ql);
57237da2899SCharles.Forsyth 		if(waserror()){
57337da2899SCharles.Forsyth 			qunlock(&rock.fs->ql);
57437da2899SCharles.Forsyth 			nexterror();
57537da2899SCharles.Forsyth 		}
57637da2899SCharles.Forsyth 		switch(omode){
57737da2899SCharles.Forsyth 		case OTRUNC|ORDWR:
57837da2899SCharles.Forsyth 		case OTRUNC|OWRITE:
57937da2899SCharles.Forsyth 			f = newfile(rock.fs, rock.fs->f[c->qid.path-1].name);
58037da2899SCharles.Forsyth 			rock.fs->f[c->qid.path-1].r--;
58137da2899SCharles.Forsyth 			c->qid.path = f - rock.fs->f;
58237da2899SCharles.Forsyth 			break;
58337da2899SCharles.Forsyth 		case OREAD:
58437da2899SCharles.Forsyth 			break;
58537da2899SCharles.Forsyth 		default:
58637da2899SCharles.Forsyth 			error(Eperm);
58737da2899SCharles.Forsyth 		}
58837da2899SCharles.Forsyth 		qunlock(&rock.fs->ql);
58937da2899SCharles.Forsyth 		poperror();
59037da2899SCharles.Forsyth 	}
59137da2899SCharles.Forsyth 
59237da2899SCharles.Forsyth 	return devopen(c, omode, 0, 0, tinyfsgen);
59337da2899SCharles.Forsyth }
59437da2899SCharles.Forsyth 
59537da2899SCharles.Forsyth static void
tinyfscreate(Chan * c,char * name,int omode,ulong perm)59637da2899SCharles.Forsyth tinyfscreate(Chan *c, char *name, int omode, ulong perm)
59737da2899SCharles.Forsyth {
59837da2899SCharles.Forsyth 	volatile struct { Tfs *fs; } rock;
59937da2899SCharles.Forsyth 	Tfile *f;
60037da2899SCharles.Forsyth 
60137da2899SCharles.Forsyth 	USED(perm);
60237da2899SCharles.Forsyth 
603*67d4cb07Sforsyth 	rock.fs = &tinyfs.fs[c->devno];
60437da2899SCharles.Forsyth 
60537da2899SCharles.Forsyth 	qlock(&rock.fs->ql);
60637da2899SCharles.Forsyth 	if(waserror()){
60737da2899SCharles.Forsyth 		qunlock(&rock.fs->ql);
60837da2899SCharles.Forsyth 		nexterror();
60937da2899SCharles.Forsyth 	}
61037da2899SCharles.Forsyth 	f = newfile(rock.fs, name);
61137da2899SCharles.Forsyth 	qunlock(&rock.fs->ql);
61237da2899SCharles.Forsyth 	poperror();
61337da2899SCharles.Forsyth 
61437da2899SCharles.Forsyth 	c->qid.path = (f - rock.fs->f)+1;
61537da2899SCharles.Forsyth 	c->qid.vers = 0;
61637da2899SCharles.Forsyth 	c->qid.type = QTFILE;
61737da2899SCharles.Forsyth 	c->mode = openmode(omode);
61837da2899SCharles.Forsyth }
61937da2899SCharles.Forsyth 
62037da2899SCharles.Forsyth static void
tinyfsremove(Chan * c)62137da2899SCharles.Forsyth tinyfsremove(Chan *c)
62237da2899SCharles.Forsyth {
62337da2899SCharles.Forsyth 	Tfs *fs;
62437da2899SCharles.Forsyth 	Tfile *f;
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth 	if(c->qid.path == Qdir)
62737da2899SCharles.Forsyth 		error(Eperm);
628*67d4cb07Sforsyth 	fs = &tinyfs.fs[c->devno];
62937da2899SCharles.Forsyth 	f = &fs->f[c->qid.path-1];
63037da2899SCharles.Forsyth 	qlock(&fs->ql);
63137da2899SCharles.Forsyth 	freefile(fs, f, Notabno);
63237da2899SCharles.Forsyth 	qunlock(&fs->ql);
63337da2899SCharles.Forsyth }
63437da2899SCharles.Forsyth 
63537da2899SCharles.Forsyth static void
tinyfsclose(Chan * c)63637da2899SCharles.Forsyth tinyfsclose(Chan *c)
63737da2899SCharles.Forsyth {
63837da2899SCharles.Forsyth 	volatile struct { Tfs *fs; } rock;
63937da2899SCharles.Forsyth 	Tfile *f, *nf;
64037da2899SCharles.Forsyth 	int i;
64137da2899SCharles.Forsyth 
642*67d4cb07Sforsyth 	rock.fs = &tinyfs.fs[c->devno];
64337da2899SCharles.Forsyth 
64437da2899SCharles.Forsyth 	qlock(&rock.fs->ql);
64537da2899SCharles.Forsyth 
64637da2899SCharles.Forsyth 	/* dereference file and remove old versions */
64737da2899SCharles.Forsyth 	if(!waserror()){
64837da2899SCharles.Forsyth 		if(c->qid.path != Qdir){
64937da2899SCharles.Forsyth 			f = &rock.fs->f[c->qid.path-1];
65037da2899SCharles.Forsyth 			f->r--;
65137da2899SCharles.Forsyth 			if(f->r == 0){
65237da2899SCharles.Forsyth 				if(f->flag & Frmonclose)
65337da2899SCharles.Forsyth 					freefile(rock.fs, f, Notabno);
65437da2899SCharles.Forsyth 				else if(f->flag & Fcreating){
65537da2899SCharles.Forsyth 					/* remove all other files with this name */
65637da2899SCharles.Forsyth 					for(i = 0; i < rock.fs->fsize; i++){
65737da2899SCharles.Forsyth 						nf = &rock.fs->f[i];
65837da2899SCharles.Forsyth 						if(f == nf)
65937da2899SCharles.Forsyth 							continue;
66037da2899SCharles.Forsyth 						if(strcmp(nf->name, f->name) == 0){
66137da2899SCharles.Forsyth 							if(nf->r)
66237da2899SCharles.Forsyth 								nf->flag |= Frmonclose;
66337da2899SCharles.Forsyth 							else
66437da2899SCharles.Forsyth 								freefile(rock.fs, nf, Notabno);
66537da2899SCharles.Forsyth 						}
66637da2899SCharles.Forsyth 					}
66737da2899SCharles.Forsyth 					f->flag &= ~Fcreating;
66837da2899SCharles.Forsyth 				}
66937da2899SCharles.Forsyth 			}
67037da2899SCharles.Forsyth 		}
67137da2899SCharles.Forsyth 		poperror();
67237da2899SCharles.Forsyth 	}
67337da2899SCharles.Forsyth 
67437da2899SCharles.Forsyth 	/* dereference rock.fs and remove on zero refs */
67537da2899SCharles.Forsyth 	rock.fs->r--;
67637da2899SCharles.Forsyth 	if(rock.fs->r == 0){
67737da2899SCharles.Forsyth 		if(rock.fs->f)
67837da2899SCharles.Forsyth 			free(rock.fs->f);
67937da2899SCharles.Forsyth 		rock.fs->f = 0;
68037da2899SCharles.Forsyth 		rock.fs->nf = 0;
68137da2899SCharles.Forsyth 		rock.fs->fsize = 0;
68237da2899SCharles.Forsyth 		if(rock.fs->map)
68337da2899SCharles.Forsyth 			free(rock.fs->map);
68437da2899SCharles.Forsyth 		rock.fs->map = 0;
68537da2899SCharles.Forsyth 		cclose(rock.fs->c);
68637da2899SCharles.Forsyth 		rock.fs->c = 0;
68737da2899SCharles.Forsyth 	}
68837da2899SCharles.Forsyth 	qunlock(&rock.fs->ql);
68937da2899SCharles.Forsyth }
69037da2899SCharles.Forsyth 
69137da2899SCharles.Forsyth static long
tinyfsread(Chan * c,void * a,long n,vlong offset)69237da2899SCharles.Forsyth tinyfsread(Chan *c, void *a, long n, vlong offset)
69337da2899SCharles.Forsyth {
69437da2899SCharles.Forsyth 	volatile struct { Tfs *fs; } rock;
69537da2899SCharles.Forsyth 	Tfile *f;
69637da2899SCharles.Forsyth 	int sofar, i, off;
69737da2899SCharles.Forsyth 	ulong bno;
69837da2899SCharles.Forsyth 	Mdata *md;
69937da2899SCharles.Forsyth 	uchar buf[Blen];
70037da2899SCharles.Forsyth 	uchar *p;
70137da2899SCharles.Forsyth 
70237da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
70337da2899SCharles.Forsyth 		return devdirread(c, a, n, 0, 0, tinyfsgen);
70437da2899SCharles.Forsyth 
70537da2899SCharles.Forsyth 	p = a;
706*67d4cb07Sforsyth 	rock.fs = &tinyfs.fs[c->devno];
70737da2899SCharles.Forsyth 	f = &rock.fs->f[c->qid.path-1];
70837da2899SCharles.Forsyth 	if(offset >= f->length)
70937da2899SCharles.Forsyth 		return 0;
71037da2899SCharles.Forsyth 
71137da2899SCharles.Forsyth 	qlock(&rock.fs->ql);
71237da2899SCharles.Forsyth 	if(waserror()){
71337da2899SCharles.Forsyth 		qunlock(&rock.fs->ql);
71437da2899SCharles.Forsyth 		nexterror();
71537da2899SCharles.Forsyth 	}
71637da2899SCharles.Forsyth 	if(n + offset >= f->length)
71737da2899SCharles.Forsyth 		n = f->length - offset;
71837da2899SCharles.Forsyth 
71937da2899SCharles.Forsyth 	/* walk to starting data block */
72037da2899SCharles.Forsyth 	if(0 && f->finger <= offset && f->fbno != Notabno){
72137da2899SCharles.Forsyth 		sofar = f->finger;
72237da2899SCharles.Forsyth 		bno = f->fbno;
72337da2899SCharles.Forsyth 	} else {
72437da2899SCharles.Forsyth 		sofar = 0;
72537da2899SCharles.Forsyth 		bno = f->dbno;
72637da2899SCharles.Forsyth 	}
72737da2899SCharles.Forsyth 	for(; sofar + Dlen <= offset; sofar += Dlen){
72837da2899SCharles.Forsyth 		md = readdata(rock.fs, bno, buf, 0);
72937da2899SCharles.Forsyth 		if(md == 0)
73037da2899SCharles.Forsyth 			error(Eio);
73137da2899SCharles.Forsyth 		bno = GETS(md->bno);
73237da2899SCharles.Forsyth 	}
73337da2899SCharles.Forsyth 
73437da2899SCharles.Forsyth 	/* read data */
73537da2899SCharles.Forsyth 	off = offset%Dlen;
73637da2899SCharles.Forsyth 	offset -= off;
73737da2899SCharles.Forsyth 	for(sofar = 0; sofar < n; sofar += i){
73837da2899SCharles.Forsyth 		md = readdata(rock.fs, bno, buf, &i);
73937da2899SCharles.Forsyth 		if(md == 0)
74037da2899SCharles.Forsyth 			error(Eio);
74137da2899SCharles.Forsyth 
74237da2899SCharles.Forsyth 		/* update finger for successful read */
74337da2899SCharles.Forsyth 		f->finger = offset;
74437da2899SCharles.Forsyth 		f->fbno = bno;
74537da2899SCharles.Forsyth 		offset += Dlen;
74637da2899SCharles.Forsyth 
74737da2899SCharles.Forsyth 		i -= off;
74837da2899SCharles.Forsyth 		if(i > n - sofar)
74937da2899SCharles.Forsyth 			i = n - sofar;
75037da2899SCharles.Forsyth 		memmove(p, md->data+off, i);
75137da2899SCharles.Forsyth 		p += i;
75237da2899SCharles.Forsyth 		bno = GETS(md->bno);
75337da2899SCharles.Forsyth 		off = 0;
75437da2899SCharles.Forsyth 	}
75537da2899SCharles.Forsyth 	qunlock(&rock.fs->ql);
75637da2899SCharles.Forsyth 	poperror();
75737da2899SCharles.Forsyth 
75837da2899SCharles.Forsyth 	return sofar;
75937da2899SCharles.Forsyth }
76037da2899SCharles.Forsyth 
76137da2899SCharles.Forsyth /*
76237da2899SCharles.Forsyth  *  if we get a write error in this routine, blocks will
76337da2899SCharles.Forsyth  *  be lost.  They should be recovered next fsinit.
76437da2899SCharles.Forsyth  */
76537da2899SCharles.Forsyth static long
tinyfswrite(Chan * c,void * a,long n,vlong offset)76637da2899SCharles.Forsyth tinyfswrite(Chan *c, void *a, long n, vlong offset)
76737da2899SCharles.Forsyth {
76837da2899SCharles.Forsyth 	Tfile *f;
76937da2899SCharles.Forsyth 	int last, next, i, finger, off, used;
77037da2899SCharles.Forsyth 	ulong bno, fbno;
77137da2899SCharles.Forsyth 	Mdata *md;
77237da2899SCharles.Forsyth 	uchar buf[Blen];
77337da2899SCharles.Forsyth 	uchar *p;
77437da2899SCharles.Forsyth 	volatile struct {
77537da2899SCharles.Forsyth 		Tfs *fs;
77637da2899SCharles.Forsyth 		ulong dbno;
77737da2899SCharles.Forsyth 	} rock;
77837da2899SCharles.Forsyth 
77937da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
78037da2899SCharles.Forsyth 		error(Eperm);
78137da2899SCharles.Forsyth 
78237da2899SCharles.Forsyth 	if(n == 0)
78337da2899SCharles.Forsyth 		return 0;
78437da2899SCharles.Forsyth 
78537da2899SCharles.Forsyth 	p = a;
786*67d4cb07Sforsyth 	rock.fs = &tinyfs.fs[c->devno];
78737da2899SCharles.Forsyth 	f = &rock.fs->f[c->qid.path-1];
78837da2899SCharles.Forsyth 
78937da2899SCharles.Forsyth 	qlock(&rock.fs->ql);
79037da2899SCharles.Forsyth 	rock.dbno = Notabno;
79137da2899SCharles.Forsyth 	if(waserror()){
79237da2899SCharles.Forsyth 		freeblocks(rock.fs, rock.dbno, Notabno);
79337da2899SCharles.Forsyth 		qunlock(&rock.fs->ql);
79437da2899SCharles.Forsyth 		nexterror();
79537da2899SCharles.Forsyth 	}
79637da2899SCharles.Forsyth 
79737da2899SCharles.Forsyth 	/* files are append only, anything else is illegal */
79837da2899SCharles.Forsyth 	if(offset != f->length)
79937da2899SCharles.Forsyth 		error("append only");
80037da2899SCharles.Forsyth 
80137da2899SCharles.Forsyth 	/* write blocks backwards */
80237da2899SCharles.Forsyth 	p += n;
80337da2899SCharles.Forsyth 	last = offset + n;
80437da2899SCharles.Forsyth 	fbno = Notabno;
80537da2899SCharles.Forsyth 	finger = 0;
80637da2899SCharles.Forsyth 	off = offset; /* so we have something signed to compare against */
80737da2899SCharles.Forsyth 	for(next = ((last-1)/Dlen)*Dlen; next >= off; next -= Dlen){
80837da2899SCharles.Forsyth 		bno = mapalloc(rock.fs);
80937da2899SCharles.Forsyth 		if(bno == Notabno)
81037da2899SCharles.Forsyth 			error("out of space");
81137da2899SCharles.Forsyth 		i = last - next;
81237da2899SCharles.Forsyth 		p -= i;
81337da2899SCharles.Forsyth 		if(last == n+offset){
81437da2899SCharles.Forsyth 			writedata(rock.fs, bno, rock.dbno, p, i, 1);
81537da2899SCharles.Forsyth 			finger = next;	/* remember for later */
81637da2899SCharles.Forsyth 			fbno = bno;
81737da2899SCharles.Forsyth 		} else {
81837da2899SCharles.Forsyth 			writedata(rock.fs, bno, rock.dbno, p, i, 0);
81937da2899SCharles.Forsyth 		}
82037da2899SCharles.Forsyth 		rock.dbno = bno;
82137da2899SCharles.Forsyth 		last = next;
82237da2899SCharles.Forsyth 	}
82337da2899SCharles.Forsyth 
82437da2899SCharles.Forsyth 	/* walk to last data block */
82537da2899SCharles.Forsyth 	md = (Mdata*)buf;
82637da2899SCharles.Forsyth 	if(0 && f->finger < offset && f->fbno != Notabno){
82737da2899SCharles.Forsyth 		next = f->finger;
82837da2899SCharles.Forsyth 		bno = f->fbno;
82937da2899SCharles.Forsyth 	} else {
83037da2899SCharles.Forsyth 		next = 0;
83137da2899SCharles.Forsyth 		bno = f->dbno;
83237da2899SCharles.Forsyth 	}
83337da2899SCharles.Forsyth 
83437da2899SCharles.Forsyth 	used = 0;
83537da2899SCharles.Forsyth 	while(bno != Notabno){
83637da2899SCharles.Forsyth 		md = readdata(rock.fs, bno, buf, &used);
83737da2899SCharles.Forsyth 		if(md == 0)
83837da2899SCharles.Forsyth 			error(Eio);
83937da2899SCharles.Forsyth 		if(md->type == Tagend){
84037da2899SCharles.Forsyth 			if(next + Dlen < offset)
84137da2899SCharles.Forsyth 				panic("devtinyfs1");
84237da2899SCharles.Forsyth 			break;
84337da2899SCharles.Forsyth 		}
84437da2899SCharles.Forsyth 		next += Dlen;
84537da2899SCharles.Forsyth 		if(next > offset)
84637da2899SCharles.Forsyth 			panic("devtinyfs1");
84737da2899SCharles.Forsyth 		bno = GETS(md->bno);
84837da2899SCharles.Forsyth 	}
84937da2899SCharles.Forsyth 
85037da2899SCharles.Forsyth 	/* point to new blocks */
85137da2899SCharles.Forsyth 	if(offset == 0){
85237da2899SCharles.Forsyth 		/* first block in a file */
85337da2899SCharles.Forsyth 		f->dbno = rock.dbno;
85437da2899SCharles.Forsyth 		writedir(rock.fs, f);
85537da2899SCharles.Forsyth 	} else {
85637da2899SCharles.Forsyth 		/* updating a current block */
85737da2899SCharles.Forsyth 		i = last - offset;
85837da2899SCharles.Forsyth 		if(i > 0){
85937da2899SCharles.Forsyth 			p -= i;
86037da2899SCharles.Forsyth 			memmove(md->data + used, p, i);
86137da2899SCharles.Forsyth 			used += i;
86237da2899SCharles.Forsyth 		}
86337da2899SCharles.Forsyth 		writedata(rock.fs, bno, rock.dbno, md->data, used, last == n+offset);
86437da2899SCharles.Forsyth 	}
86537da2899SCharles.Forsyth 	f->length += n;
86637da2899SCharles.Forsyth 
86737da2899SCharles.Forsyth 	/* update finger */
86837da2899SCharles.Forsyth 	if(fbno != Notabno){
86937da2899SCharles.Forsyth 		f->finger = finger;
87037da2899SCharles.Forsyth 		f->fbno =  fbno;
87137da2899SCharles.Forsyth 	}
87237da2899SCharles.Forsyth 	poperror();
87337da2899SCharles.Forsyth 	qunlock(&rock.fs->ql);
87437da2899SCharles.Forsyth 
87537da2899SCharles.Forsyth 	return n;
87637da2899SCharles.Forsyth }
87737da2899SCharles.Forsyth 
87837da2899SCharles.Forsyth Dev tinyfsdevtab = {
87937da2899SCharles.Forsyth 	'F',
88037da2899SCharles.Forsyth 	"tinyfs",
88137da2899SCharles.Forsyth 
882*67d4cb07Sforsyth 	devreset,
88337da2899SCharles.Forsyth 	devinit,
884*67d4cb07Sforsyth 	devshutdown,
88537da2899SCharles.Forsyth 	tinyfsattach,
88637da2899SCharles.Forsyth 	tinyfswalk,
88737da2899SCharles.Forsyth 	tinyfsstat,
88837da2899SCharles.Forsyth 	tinyfsopen,
88937da2899SCharles.Forsyth 	tinyfscreate,
89037da2899SCharles.Forsyth 	tinyfsclose,
89137da2899SCharles.Forsyth 	tinyfsread,
89237da2899SCharles.Forsyth 	devbread,
89337da2899SCharles.Forsyth 	tinyfswrite,
89437da2899SCharles.Forsyth 	devbwrite,
89537da2899SCharles.Forsyth 	tinyfsremove,
89637da2899SCharles.Forsyth 	devwstat
89737da2899SCharles.Forsyth };
898