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