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