1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "fs.h"
7
8 typedef struct Tag Tag;
9
10 /*
11 * tags on block
12 */
13 enum
14 {
15 Tnone = 0,
16 Tsuper, /* the super block */
17 Tdir, /* directory contents */
18 Tind1, /* points to blocks */
19 Tind2, /* points to Tind1 */
20 Tfile, /* file contents */
21 Tfree, /* in free list */
22 Tbuck, /* cache fs bucket */
23 Tvirgo, /* fake worm virgin bits */
24 Tcache, /* cw cache things */
25 MAXTAG
26 };
27
28 #define QPDIR 0x80000000L
29 #define QPNONE 0
30 #define QPROOT 1
31 #define QPSUPER 2
32
33 /* DONT TOUCH, this is the disk structure */
34 struct Tag
35 {
36 short pad;
37 short tag;
38 long path;
39 };
40
41 static int thisblock = -1;
42 static Fs *thisfs;
43 static uchar *block;
44
45 /*
46 * we end up reading 2x or 3x the number of blocks we need to read.
47 * this is okay because we need to read so few. if it wasn't okay, we could
48 * have getblock return a pointer to a block, and keep a cache of the last
49 * three read blocks. that would get us down to the minimum.
50 * but this is fine.
51 */
52 static int
getblock(Fs * fs,ulong n)53 getblock(Fs *fs, ulong n)
54 {
55 if(!block)
56 block = malloc(16384);
57
58 if(thisblock == n && thisfs == fs)
59 return 0;
60 thisblock = -1;
61 if(fs->diskseek(fs, (vlong)n*fs->kfs.RBUFSIZE) < 0)
62 return -1;
63 if(fs->diskread(fs, block, fs->kfs.RBUFSIZE) != fs->kfs.RBUFSIZE)
64 return -1;
65 thisblock = n;
66 thisfs = fs;
67
68 return 1;
69 }
70
71 static int
checktag(Fs * fs,uchar * block,int tag,long qpath)72 checktag(Fs *fs, uchar *block, int tag, long qpath)
73 {
74 Tag *t;
75
76 t = (Tag*)(block+fs->kfs.BUFSIZE);
77 if(t->tag != tag)
78 return -1;
79 if(qpath != QPNONE && (qpath&~QPDIR) != t->path)
80 return -1;
81 return 1;
82 }
83
84 static int
getblocktag(Fs * fs,ulong n,int tag,long qpath)85 getblocktag(Fs *fs, ulong n, int tag, long qpath)
86 {
87 if(getblock(fs, n) < 0 || checktag(fs, block, tag, qpath) < 0)
88 return -1;
89 return 1;
90 }
91
92 static int
readinfo(Fs * fs)93 readinfo(Fs *fs)
94 {
95 fs->kfs.RBUFSIZE = 512;
96 if(getblock(fs, 0) < 0)
97 return -1;
98
99 if(memcmp(block+256, "kfs wren device\n", 16) != 0)
100 return -1;
101
102 fs->kfs.RBUFSIZE = atoi((char*)block+256+16);
103 if(!fs->kfs.RBUFSIZE || (fs->kfs.RBUFSIZE&(fs->kfs.RBUFSIZE-1)))
104 return -1;
105
106 fs->kfs.BUFSIZE = fs->kfs.RBUFSIZE - sizeof(Tag);
107 fs->kfs.DIRPERBUF = fs->kfs.BUFSIZE / sizeof(Dentry);
108 fs->kfs.INDPERBUF = fs->kfs.BUFSIZE / sizeof(long);
109 fs->kfs.INDPERBUF2 = fs->kfs.INDPERBUF * fs->kfs.INDPERBUF;
110
111 return 1;
112 }
113
114 static int
readroot(Fs * fs,Dentry * d)115 readroot(Fs *fs, Dentry *d)
116 {
117 Dentry *d2;
118
119 if(getblocktag(fs, 2, Tdir, QPROOT) < 0)
120 return -1;
121 d2 = (Dentry*)block;
122 if(strcmp(d2->name, "/") != 0)
123 return -1;
124 *d = *(Dentry*)block;
125 return 1;
126 }
127
128 static long
indfetch(Fs * fs,long addr,long off,int tag,long path)129 indfetch(Fs *fs, long addr, long off, int tag, long path)
130 {
131 if(getblocktag(fs, addr, tag, path) < 0)
132 return -1;
133 return ((long*)block)[off];
134 }
135
136 static long
rel2abs(Fs * fs,Dentry * d,long a)137 rel2abs(Fs *fs, Dentry *d, long a)
138 {
139 long addr;
140
141 if(a < NDBLOCK)
142 return d->dblock[a];
143 a -= NDBLOCK;
144 if(a < fs->kfs.INDPERBUF){
145 if(d->iblock == 0)
146 return 0;
147 addr = indfetch(fs, d->iblock, a, Tind1, d->qid.path);
148 if(addr == 0)
149 print("rel2abs indfetch 0 %s %ld\n", d->name, a);
150 return addr;
151 }
152 a -= fs->kfs.INDPERBUF;
153 if(a < fs->kfs.INDPERBUF2){
154 if(d->diblock == 0)
155 return 0;
156 addr = indfetch(fs, d->diblock, a/fs->kfs.INDPERBUF, Tind2, d->qid.path);
157 if(addr == 0){
158 print("rel2abs indfetch 0 %s %ld\n", d->name, a/fs->kfs.INDPERBUF);
159 return 0;
160 }
161 addr = indfetch(fs, addr, a%fs->kfs.INDPERBUF, Tind1, d->qid.path);
162 return addr;
163 }
164 print("rel2abs trip ind %s %ld\n", d->name, a);
165 return -1;
166 }
167
168 static int
readdentry(Fs * fs,Dentry * d,int n,Dentry * e)169 readdentry(Fs *fs, Dentry *d, int n, Dentry *e)
170 {
171 long addr, m;
172
173 m = n/fs->kfs.DIRPERBUF;
174 if((addr = rel2abs(fs, d, m)) <= 0)
175 return addr;
176 if(getblocktag(fs, addr, Tdir, d->qid.path) < 0)
177 return -1;
178 *e = *(Dentry*)(block+(n%fs->kfs.DIRPERBUF)*sizeof(Dentry));
179 return 1;
180 }
181
182 static int
getdatablock(Fs * fs,Dentry * d,long a)183 getdatablock(Fs *fs, Dentry *d, long a)
184 {
185 long addr;
186
187 if((addr = rel2abs(fs, d, a)) == 0)
188 return -1;
189 return getblocktag(fs, addr, Tfile, QPNONE);
190 }
191
192 static int
walk(Fs * fs,Dentry * d,char * name,Dentry * e)193 walk(Fs *fs, Dentry *d, char *name, Dentry *e)
194 {
195 int i, n;
196 Dentry x;
197
198 for(i=0;; i++){
199 if((n=readdentry(fs, d, i, &x)) <= 0)
200 return n;
201 if(strcmp(x.name, name) == 0){
202 *e = x;
203 return 1;
204 }
205 }
206 }
207
208 static long
kfsread(File * f,void * va,long len)209 kfsread(File *f, void *va, long len)
210 {
211 uchar *a;
212 long tot, off, o, n;
213 Fs *fs;
214
215 a = va;
216 fs = f->fs;
217 off = f->kfs.off;
218 tot = 0;
219 while(tot < len){
220 if(getdatablock(fs, &f->kfs, off/fs->kfs.BUFSIZE) < 0)
221 return -1;
222 o = off%fs->kfs.BUFSIZE;
223 n = fs->kfs.BUFSIZE - o;
224 if(n > len-tot)
225 n = len-tot;
226 memmove(a+tot, block+o, n);
227 off += n;
228 tot += n;
229 }
230 f->kfs.off = off;
231 return tot;
232 }
233
234 static int
kfswalk(File * f,char * name)235 kfswalk(File *f, char *name)
236 {
237 int n;
238
239 n = walk(f->fs, &f->kfs, name, &f->kfs);
240 if(n < 0)
241 return -1;
242 f->kfs.off = 0;
243 return 1;
244 }
245
246 int
kfsinit(Fs * fs)247 kfsinit(Fs *fs)
248 {
249 if(readinfo(fs) < 0 || readroot(fs, &fs->root.kfs) < 0)
250 return -1;
251
252 fs->root.fs = fs;
253 fs->read = kfsread;
254 fs->walk = kfswalk;
255 return 0;
256 }
257