/* * a pity the code isn't also tiny... */#include "u.h"#include "../port/lib.h"#include "../port/error.h"#include "mem.h"#include "dat.h"#include "fns.h" enum{ Qdir, Qmedium, Maxfs= 10, /* max file systems */ Blen= 48, /* block length */ Nlen= 28, /* name length */ Dlen= Blen - 4, Tagdir= 'd', Tagdata= 'D', Tagend= 'e', Tagfree= 'f', Notapin= 0xffff, Notabno= 0xffff, Fcreating= 1, Frmonclose= 2}; /* representation of a Tdir on medium */typedef struct Mdir Mdir;struct Mdir { uchar type; uchar bno[2]; uchar pin[2]; char name[Nlen]; char pad[Blen - Nlen - 6]; uchar sum;}; /* representation of a Tdata/Tend on medium */typedef struct Mdata Mdata;struct Mdata { uchar type; uchar bno[2]; uchar data[Dlen]; uchar sum;}; typedef struct Tfile Tfile;struct Tfile { int r; char name[Nlen]; ushort bno; ushort dbno; ushort pin; uchar flag; ulong length; /* hint to avoid egregious reading */ ushort fbno; ulong finger;}; typedef struct Tfs Tfs;struct Tfs { QLock ql; int r; Chan *c; uchar *map; int nblocks; Tfile *f; int nf; int fsize;}; static struct { Tfs fs[Maxfs];} tinyfs; #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 ucharchecksum(uchar *p){ uchar *e; uchar s; s = 0; for(e = p + Blen; p < e; p++) s += *p; return s;} static voidmapclr(Tfs *fs, ulong bno){ fs->map[bno>>3] &= ~(1<<(bno&7));} static voidmapset(Tfs *fs, ulong bno){ fs->map[bno>>3] |= 1<<(bno&7);} static intisalloced(Tfs *fs, ulong bno){ return fs->map[bno>>3] & (1<<(bno&7));} static intmapalloc(Tfs *fs){ int i, j, lim; uchar x; lim = (fs->nblocks + 8 - 1)/8; for(i = 0; i < lim; i++){ x = fs->map[i]; if(x == 0xff) continue; for(j = 0; j < 8; j++) if((x & (1<<j)) == 0){ fs->map[i] = x|(1<<j); return i*8 + j; } } return Notabno;} static Mdir*validdir(Tfs *fs, uchar *p){ Mdir *md; ulong x; if(checksum(p) != 0) return 0; if(p[0] != Tagdir) return 0; md = (Mdir*)p; x = GETS(md->bno); if(x >= fs->nblocks) return 0; return md;} static Mdata*validdata(Tfs *fs, uchar *p, int *lenp){ Mdata *md; ulong x; if(checksum(p) != 0) return 0; md = (Mdata*)p; switch(md->type){ case Tagdata: x = GETS(md->bno); if(x >= fs->nblocks) return 0; if(lenp) *lenp = Dlen; break; case Tagend: x = GETS(md->bno); if(x > Dlen) return 0; if(lenp) *lenp = x; break; default: return 0; } return md;} static Mdata*readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp){ if(bno >= fs->nblocks) return 0; if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) error(Eio); return validdata(fs, buf, lenp);} static voidwritedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last){ Mdata md; if(bno >= fs->nblocks) error(Eio); if(len > Dlen) len = Dlen; if(len < 0) error(Eio); memset(&md, 0, sizeof(md)); if(last){ md.type = Tagend; PUTS(md.bno, len); } else { md.type = Tagdata; PUTS(md.bno, next); } memmove(md.data, buf, len); md.sum = 0 - checksum((uchar*)&md); if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen) error(Eio);} static voidwritedir(Tfs *fs, Tfile *f){ Mdir *md; uchar buf[Blen]; if(f->bno == Notabno) return; 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); md->sum = 0 - checksum(buf); if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) error(Eio);} static voidfreeblocks(Tfs *fs, ulong bno, ulong bend){ uchar buf[Blen]; Mdata *md; if(waserror()) return; while(bno != bend && bno != Notabno){ mapclr(fs, bno); if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) break; md = validdata(fs, buf, 0); if(md == 0) break; if(md->type == Tagend) break; bno = GETS(md->bno); } poperror();} static voidfreefile(Tfs *fs, Tfile *f, ulong bend){ uchar buf[Blen]; /* remove blocks from map */ freeblocks(fs, f->dbno, bend); /* change file type to free on medium */ if(f->bno != Notabno){ memset(buf, 0x55, Blen); devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); mapclr(fs, f->bno); } /* forget we ever knew about it */ memset(f, 0, sizeof(*f));} static voidexpand(Tfs *fs){ Tfile *f; fs->fsize += 8; f = malloc(fs->fsize*sizeof(*f)); if(f == nil) error(Enomem); if(fs->f){ memmove(f, fs->f, fs->nf*sizeof(*f)); free(fs->f); } fs->f = f;} static Tfile*newfile(Tfs *fs, char *name){ int i; volatile struct { Tfile *f; Tfs *fs; } rock; /* find free entry in file table */ rock.f = 0; rock.fs = fs; for(;;) { for(i = 0; i < rock.fs->fsize; i++){ rock.f = &rock.fs->f[i]; if(rock.f->name[0] == 0){ strncpy(rock.f->name, name, sizeof(rock.f->name)-1); break; } } if(i < rock.fs->fsize){ if(i >= rock.fs->nf) rock.fs->nf = i+1; break; } expand(rock.fs); } rock.f->flag = Fcreating; rock.f->dbno = Notabno; rock.f->bno = mapalloc(rock.fs); rock.f->fbno = Notabno; rock.f->r = 1; rock.f->pin = up->env->pgrp->pin; /* write directory block */ if(waserror()){ freefile(rock.fs, rock.f, Notabno); nexterror(); } if(rock.f->bno == Notabno) error("out of space"); writedir(rock.fs, rock.f); poperror(); return rock.f;} /* * Read the whole medium and build a file table and used * block bitmap. Inconsistent files are purged. The medium * had better be small or this could take a while. */static voidtfsinit(Tfs *fs){ uchar dbuf[STATFIXLEN+4*KNAMELEN]; Dir d; uchar buf[Blen]; ulong x, bno; int n, done; Tfile *f; Mdir *mdir; Mdata *mdata; n = devtab[fs->c->type]->stat(fs->c, dbuf, sizeof(dbuf)); if(n == 0) error(Eshortstat); n = convM2D(dbuf, n, &d, nil); if(n == 0) error(Eshortstat); fs->nblocks = d.length/Blen; if(fs->nblocks < 3) error("tinyfs medium too small"); /* bitmap for block usage */ x = (fs->nblocks + 8 - 1)/8; fs->map = malloc(x); if(fs->map == nil) error(Enomem); memset(fs->map, 0x0, x); for(bno = fs->nblocks; bno < x*8; bno++) mapset(fs, bno); /* find files */ for(bno = 0; bno < fs->nblocks; bno++){ n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen) break; mdir = validdir(fs, buf); if(mdir == 0) continue; if(fs->nf >= fs->fsize) expand(fs); 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; f->fbno = Notabno; } /* follow files */ for(f = fs->f; f < &(fs->f[fs->nf]); f++){ bno = f->dbno; for(done = 0; !done;) { if(isalloced(fs, bno)){ freefile(fs, f, bno); break; } n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen){ freefile(fs, f, bno); break; } mdata = validdata(fs, buf, 0); if(mdata == 0){ freefile(fs, f, bno); break; } mapset(fs, bno); switch(mdata->type){ case Tagdata: bno = GETS(mdata->bno); f->length += Dlen; break; case Tagend: f->length += GETS(mdata->bno); done = 1; break; } if(done) f->flag &= ~Fcreating; } }} /* * single directory */static inttinyfsgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp){ Tfs *fs; Tfile *f; Qid qid; USED(ntab); USED(tab); fs = &tinyfs.fs[c->dev]; if(i >= fs->nf) return -1; if(i == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, ".", 0, eve, 0555, dp); return 1; } f = &fs->f[i]; if(f->name[0] == 0) return 0; mkqid(&qid, i, 0, QTFILE); devdir(c, qid, f->name, f->length, eve, 0664, dp); return 1;} static voidtinyfsinit(void){ if(Nlen > KNAMELEN) panic("tinyfsinit");} /* * specifier is the name of a device in /dev */static Chan*tinyfsattach(char *spec){ Tfs *fs; Chan *c; volatile struct { Chan *cc; } rock; int i; char buf[KNAMELEN*3]; if(*spec == 0) error("bad specifier"); Lines 1–500 of 915. Load more
/* * a pity the code isn't also tiny... */ #include "u.h" #include "../port/lib.h" #include "../port/error.h" #include "mem.h" #include "dat.h" #include "fns.h" enum{ Qdir, Qmedium, Maxfs= 10, /* max file systems */ Blen= 48, /* block length */ Nlen= 28, /* name length */ Dlen= Blen - 4, Tagdir= 'd', Tagdata= 'D', Tagend= 'e', Tagfree= 'f', Notapin= 0xffff, Notabno= 0xffff, Fcreating= 1, Frmonclose= 2 }; /* representation of a Tdir on medium */ typedef struct Mdir Mdir; struct Mdir { uchar type; uchar bno[2]; uchar pin[2]; char name[Nlen]; char pad[Blen - Nlen - 6]; uchar sum; }; /* representation of a Tdata/Tend on medium */ typedef struct Mdata Mdata; struct Mdata { uchar type; uchar bno[2]; uchar data[Dlen]; uchar sum; }; typedef struct Tfile Tfile; struct Tfile { int r; char name[Nlen]; ushort bno; ushort dbno; ushort pin; uchar flag; ulong length; /* hint to avoid egregious reading */ ushort fbno; ulong finger; }; typedef struct Tfs Tfs; struct Tfs { QLock ql; int r; Chan *c; uchar *map; int nblocks; Tfile *f; int nf; int fsize; }; static struct { Tfs fs[Maxfs]; } tinyfs; #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; s = 0; for(e = p + Blen; p < e; p++) s += *p; return s; } static void mapclr(Tfs *fs, ulong bno) { fs->map[bno>>3] &= ~(1<<(bno&7)); } static void mapset(Tfs *fs, ulong bno) { fs->map[bno>>3] |= 1<<(bno&7); } static int isalloced(Tfs *fs, ulong bno) { return fs->map[bno>>3] & (1<<(bno&7)); } static int mapalloc(Tfs *fs) { int i, j, lim; uchar x; lim = (fs->nblocks + 8 - 1)/8; for(i = 0; i < lim; i++){ x = fs->map[i]; if(x == 0xff) continue; for(j = 0; j < 8; j++) if((x & (1<<j)) == 0){ fs->map[i] = x|(1<<j); return i*8 + j; } } return Notabno; } static Mdir* validdir(Tfs *fs, uchar *p) { Mdir *md; ulong x; if(checksum(p) != 0) return 0; if(p[0] != Tagdir) return 0; md = (Mdir*)p; x = GETS(md->bno); if(x >= fs->nblocks) return 0; return md; } static Mdata* validdata(Tfs *fs, uchar *p, int *lenp) { Mdata *md; ulong x; if(checksum(p) != 0) return 0; md = (Mdata*)p; switch(md->type){ case Tagdata: x = GETS(md->bno); if(x >= fs->nblocks) return 0; if(lenp) *lenp = Dlen; break; case Tagend: x = GETS(md->bno); if(x > Dlen) return 0; if(lenp) *lenp = x; break; default: return 0; } return md; } static Mdata* readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp) { if(bno >= fs->nblocks) return 0; if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) error(Eio); return validdata(fs, buf, lenp); } static void writedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last) { Mdata md; if(bno >= fs->nblocks) error(Eio); if(len > Dlen) len = Dlen; if(len < 0) error(Eio); memset(&md, 0, sizeof(md)); if(last){ md.type = Tagend; PUTS(md.bno, len); } else { md.type = Tagdata; PUTS(md.bno, next); } memmove(md.data, buf, len); md.sum = 0 - checksum((uchar*)&md); if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen) error(Eio); } static void writedir(Tfs *fs, Tfile *f) { Mdir *md; uchar buf[Blen]; if(f->bno == Notabno) return; 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); md->sum = 0 - checksum(buf); if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) error(Eio); } static void freeblocks(Tfs *fs, ulong bno, ulong bend) { uchar buf[Blen]; Mdata *md; if(waserror()) return; while(bno != bend && bno != Notabno){ mapclr(fs, bno); if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) break; md = validdata(fs, buf, 0); if(md == 0) break; if(md->type == Tagend) break; bno = GETS(md->bno); } poperror(); } static void freefile(Tfs *fs, Tfile *f, ulong bend) { uchar buf[Blen]; /* remove blocks from map */ freeblocks(fs, f->dbno, bend); /* change file type to free on medium */ if(f->bno != Notabno){ memset(buf, 0x55, Blen); devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); mapclr(fs, f->bno); } /* forget we ever knew about it */ memset(f, 0, sizeof(*f)); } static void expand(Tfs *fs) { Tfile *f; fs->fsize += 8; f = malloc(fs->fsize*sizeof(*f)); if(f == nil) error(Enomem); if(fs->f){ memmove(f, fs->f, fs->nf*sizeof(*f)); free(fs->f); } fs->f = f; } static Tfile* newfile(Tfs *fs, char *name) { int i; volatile struct { Tfile *f; Tfs *fs; } rock; /* find free entry in file table */ rock.f = 0; rock.fs = fs; for(;;) { for(i = 0; i < rock.fs->fsize; i++){ rock.f = &rock.fs->f[i]; if(rock.f->name[0] == 0){ strncpy(rock.f->name, name, sizeof(rock.f->name)-1); break; } } if(i < rock.fs->fsize){ if(i >= rock.fs->nf) rock.fs->nf = i+1; break; } expand(rock.fs); } rock.f->flag = Fcreating; rock.f->dbno = Notabno; rock.f->bno = mapalloc(rock.fs); rock.f->fbno = Notabno; rock.f->r = 1; rock.f->pin = up->env->pgrp->pin; /* write directory block */ if(waserror()){ freefile(rock.fs, rock.f, Notabno); nexterror(); } if(rock.f->bno == Notabno) error("out of space"); writedir(rock.fs, rock.f); poperror(); return rock.f; } /* * Read the whole medium and build a file table and used * block bitmap. Inconsistent files are purged. The medium * had better be small or this could take a while. */ static void tfsinit(Tfs *fs) { uchar dbuf[STATFIXLEN+4*KNAMELEN]; Dir d; uchar buf[Blen]; ulong x, bno; int n, done; Tfile *f; Mdir *mdir; Mdata *mdata; n = devtab[fs->c->type]->stat(fs->c, dbuf, sizeof(dbuf)); if(n == 0) error(Eshortstat); n = convM2D(dbuf, n, &d, nil); if(n == 0) error(Eshortstat); fs->nblocks = d.length/Blen; if(fs->nblocks < 3) error("tinyfs medium too small"); /* bitmap for block usage */ x = (fs->nblocks + 8 - 1)/8; fs->map = malloc(x); if(fs->map == nil) error(Enomem); memset(fs->map, 0x0, x); for(bno = fs->nblocks; bno < x*8; bno++) mapset(fs, bno); /* find files */ for(bno = 0; bno < fs->nblocks; bno++){ n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen) break; mdir = validdir(fs, buf); if(mdir == 0) continue; if(fs->nf >= fs->fsize) expand(fs); 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; f->fbno = Notabno; } /* follow files */ for(f = fs->f; f < &(fs->f[fs->nf]); f++){ bno = f->dbno; for(done = 0; !done;) { if(isalloced(fs, bno)){ freefile(fs, f, bno); break; } n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen){ freefile(fs, f, bno); break; } mdata = validdata(fs, buf, 0); if(mdata == 0){ freefile(fs, f, bno); break; } mapset(fs, bno); switch(mdata->type){ case Tagdata: bno = GETS(mdata->bno); f->length += Dlen; break; case Tagend: f->length += GETS(mdata->bno); done = 1; break; } if(done) f->flag &= ~Fcreating; } } } /* * single directory */ static int tinyfsgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp) { Tfs *fs; Tfile *f; Qid qid; USED(ntab); USED(tab); fs = &tinyfs.fs[c->dev]; if(i >= fs->nf) return -1; if(i == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, ".", 0, eve, 0555, dp); return 1; } f = &fs->f[i]; if(f->name[0] == 0) return 0; mkqid(&qid, i, 0, QTFILE); devdir(c, qid, f->name, f->length, eve, 0664, dp); return 1; } static void tinyfsinit(void) { if(Nlen > KNAMELEN) panic("tinyfsinit"); } /* * specifier is the name of a device in /dev */ static Chan* tinyfsattach(char *spec) { Tfs *fs; Chan *c; volatile struct { Chan *cc; } rock; int i; char buf[KNAMELEN*3]; if(*spec == 0) error("bad specifier");