xref: /inferno-os/os/boot/pc/kfsboot.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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