#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "fs.h" typedef struct Tag Tag; /* * tags on block */ enum { Tnone = 0, Tsuper, /* the super block */ Tdir, /* directory contents */ Tind1, /* points to blocks */ Tind2, /* points to Tind1 */ Tfile, /* file contents */ Tfree, /* in free list */ Tbuck, /* cache fs bucket */ Tvirgo, /* fake worm virgin bits */ Tcache, /* cw cache things */ MAXTAG }; #define QPDIR 0x80000000L #define QPNONE 0 #define QPROOT 1 #define QPSUPER 2 /* DONT TOUCH, this is the disk structure */ struct Tag { short pad; short tag; long path; }; static int thisblock = -1; static Fs *thisfs; static uchar *block; /* * we end up reading 2x or 3x the number of blocks we need to read. * this is okay because we need to read so few. if it wasn't okay, we could * have getblock return a pointer to a block, and keep a cache of the last * three read blocks. that would get us down to the minimum. * but this is fine. */ static int getblock(Fs *fs, ulong n) { if(!block) block = malloc(16384); if(thisblock == n && thisfs == fs) return 0; thisblock = -1; if(fs->diskseek(fs, (vlong)n*fs->kfs.RBUFSIZE) < 0) return -1; if(fs->diskread(fs, block, fs->kfs.RBUFSIZE) != fs->kfs.RBUFSIZE) return -1; thisblock = n; thisfs = fs; return 1; } static int checktag(Fs *fs, uchar *block, int tag, long qpath) { Tag *t; t = (Tag*)(block+fs->kfs.BUFSIZE); if(t->tag != tag) return -1; if(qpath != QPNONE && (qpath&~QPDIR) != t->path) return -1; return 1; } static int getblocktag(Fs *fs, ulong n, int tag, long qpath) { if(getblock(fs, n) < 0 || checktag(fs, block, tag, qpath) < 0) return -1; return 1; } static int readinfo(Fs *fs) { fs->kfs.RBUFSIZE = 512; if(getblock(fs, 0) < 0) return -1; if(memcmp(block+256, "kfs wren device\n", 16) != 0) return -1; fs->kfs.RBUFSIZE = atoi((char*)block+256+16); if(!fs->kfs.RBUFSIZE || (fs->kfs.RBUFSIZE&(fs->kfs.RBUFSIZE-1))) return -1; fs->kfs.BUFSIZE = fs->kfs.RBUFSIZE - sizeof(Tag); fs->kfs.DIRPERBUF = fs->kfs.BUFSIZE / sizeof(Dentry); fs->kfs.INDPERBUF = fs->kfs.BUFSIZE / sizeof(long); fs->kfs.INDPERBUF2 = fs->kfs.INDPERBUF * fs->kfs.INDPERBUF; return 1; } static int readroot(Fs *fs, Dentry *d) { Dentry *d2; if(getblocktag(fs, 2, Tdir, QPROOT) < 0) return -1; d2 = (Dentry*)block; if(strcmp(d2->name, "/") != 0) return -1; *d = *(Dentry*)block; return 1; } static long indfetch(Fs *fs, long addr, long off, int tag, long path) { if(getblocktag(fs, addr, tag, path) < 0) return -1; return ((long*)block)[off]; } static long rel2abs(Fs *fs, Dentry *d, long a) { long addr; if(a < NDBLOCK) return d->dblock[a]; a -= NDBLOCK; if(a < fs->kfs.INDPERBUF){ if(d->iblock == 0) return 0; addr = indfetch(fs, d->iblock, a, Tind1, d->qid.path); if(addr == 0) print("rel2abs indfetch 0 %s %ld\n", d->name, a); return addr; } a -= fs->kfs.INDPERBUF; if(a < fs->kfs.INDPERBUF2){ if(d->diblock == 0) return 0; addr = indfetch(fs, d->diblock, a/fs->kfs.INDPERBUF, Tind2, d->qid.path); if(addr == 0){ print("rel2abs indfetch 0 %s %ld\n", d->name, a/fs->kfs.INDPERBUF); return 0; } addr = indfetch(fs, addr, a%fs->kfs.INDPERBUF, Tind1, d->qid.path); return addr; } print("rel2abs trip ind %s %ld\n", d->name, a); return -1; } static int readdentry(Fs *fs, Dentry *d, int n, Dentry *e) { long addr, m; m = n/fs->kfs.DIRPERBUF; if((addr = rel2abs(fs, d, m)) <= 0) return addr; if(getblocktag(fs, addr, Tdir, d->qid.path) < 0) return -1; *e = *(Dentry*)(block+(n%fs->kfs.DIRPERBUF)*sizeof(Dentry)); return 1; } static int getdatablock(Fs *fs, Dentry *d, long a) { long addr; if((addr = rel2abs(fs, d, a)) == 0) return -1; return getblocktag(fs, addr, Tfile, QPNONE); } static int walk(Fs *fs, Dentry *d, char *name, Dentry *e) { int i, n; Dentry x; for(i=0;; i++){ if((n=readdentry(fs, d, i, &x)) <= 0) return n; if(strcmp(x.name, name) == 0){ *e = x; return 1; } } } static long kfsread(File *f, void *va, long len) { uchar *a; long tot, off, o, n; Fs *fs; a = va; fs = f->fs; off = f->kfs.off; tot = 0; while(tot < len){ if(getdatablock(fs, &f->kfs, off/fs->kfs.BUFSIZE) < 0) return -1; o = off%fs->kfs.BUFSIZE; n = fs->kfs.BUFSIZE - o; if(n > len-tot) n = len-tot; memmove(a+tot, block+o, n); off += n; tot += n; } f->kfs.off = off; return tot; } static int kfswalk(File *f, char *name) { int n; n = walk(f->fs, &f->kfs, name, &f->kfs); if(n < 0) return -1; f->kfs.off = 0; return 1; } int kfsinit(Fs *fs) { if(readinfo(fs) < 0 || readroot(fs, &fs->root.kfs) < 0) return -1; fs->root.fs = fs; fs->read = kfsread; fs->walk = kfswalk; return 0; }