| ---
tfs.c (8901B)
---
1 #include "std.h"
2 #include "dat.h"
3
4 enum
5 {
6 Qroot,
7 Qfactotum,
8 Qrpc,
9 Qkeylist,
10 Qprotolist,
11 Qconfirm,
12 Qlog,
13 Qctl,
14 Qneedkey,
15 Qconv
16 };
17
18 static int qtop;
19
20 Qid
21 mkqid(int type, int path)
22 {
23 Qid q;
24
25 q.type = type;
26 q.path = path;
27 q.vers = 0;
28 return q;
29 }
30
31 static struct
32 {
33 char *name;
34 int qidpath;
35 ulong perm;
36 } dirtab[] = {
37 /* positions of confirm and needkey known below */
38 "confirm", Qconfirm, 0600|DMEXCL,
39 "needkey", Qneedkey, 0600|DMEXCL,
40 "ctl", Qctl, 0600,
41 "rpc", Qrpc, 0666,
42 "proto", Qprotolist, 0444,
43 "log", Qlog, 0600|DMEXCL,
44 "conv", Qconv, 0400
45 };
46
47 static void
48 fillstat(Dir *dir, char *name, int type, int path, ulong perm)
49 {
50 dir->name = estrdup(name);
51 dir->uid = estrdup(owner);
52 dir->gid = estrdup(owner);
53 dir->mode = perm;
54 dir->length = 0;
55 dir->qid = mkqid(type, path);
56 dir->atime = time(0);
57 dir->mtime = time(0);
58 dir->muid = estrdup("");
59 }
60
61 static int
62 rootdirgen(int n, Dir *dir, void *v)
63 {
64 USED(v);
65
66 if(n > 0)
67 return -1;
68
69 fillstat(dir, factname, QTDIR, Qfactotum, DMDIR|0555);
70 return 0;
71 }
72
73 static int
74 fsdirgen(int n, Dir *dir, void *v)
75 {
76 USED(v);
77
78 if(n >= nelem(dirtab))
79 return -1;
80 fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
81 return 0;
82 }
83
84 static char*
85 fswalk1(Fid *fid, char *name, Qid *qid)
86 {
87 int i;
88
89 switch((int)fid->qid.path){
90 default:
91 return "fswalk1: cannot happen";
92 case Qroot:
93 if(strcmp(name, factname) == 0){
94 *qid = mkqid(QTDIR, Qfactotum);
95 fid->qid = *qid;
96 return nil;
97 }
98 if(strcmp(name, "..") == 0){
99 *qid = fid->qid;
100 return nil;
101 }
102 return "not found";
103 case Qfactotum:
104 for(i=0; iqid = *qid;
108 return nil;
109 }
110 if(strcmp(name, "..") == 0){
111 *qid = mkqid(QTDIR, qtop);
112 fid->qid = *qid;
113 return nil;
114 }
115 return "not found";
116 }
117 }
118
119 static void
120 fsstat(Req *r)
121 {
122 int i, path;
123
124 path = r->fid->qid.path;
125 switch(path){
126 case Qroot:
127 fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
128 break;
129 case Qfactotum:
130 fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
131 break;
132 default:
133 for(i=0; id, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
136 goto Break2;
137 }
138 respond(r, "file not found");
139 break;
140 }
141 Break2:
142 respond(r, nil);
143 }
144
145 static int
146 readlist(int off, int (*gen)(int, char*, uint), Req *r)
147 {
148 char *a, *ea;
149 int n;
150
151 a = r->ofcall.data;
152 ea = a+r->ifcall.count;
153 for(;;){
154 n = (*gen)(off, a, ea-a);
155 if(n == 0){
156 r->ofcall.count = a - (char*)r->ofcall.data;
157 return off;
158 }
159 a += n;
160 off++;
161 }
162 /* not reached */
163 }
164
165 static int
166 keylist(int i, char *a, uint nn)
167 {
168 int n;
169 char buf[4096];
170 Key *k;
171
172 if(i >= ring.nkey)
173 return 0;
174
175 k = ring.key[i];
176 k->attr = sortattr(k->attr);
177 n = snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
178 if(n >= sizeof(buf)-5)
179 strcpy(buf+sizeof(buf)-5, "...\n");
180 n = strlen(buf);
181 if(n > nn)
182 return 0;
183 memmove(a, buf, n);
184 return n;
185 }
186
187 static int
188 protolist(int i, char *a, uint n)
189 {
190 if(prototab[i] == nil)
191 return 0;
192 if(strlen(prototab[i]->name)+1 > n)
193 return 0;
194 n = strlen(prototab[i]->name)+1;
195 memmove(a, prototab[i]->name, n-1);
196 a[n-1] = '\n';
197 return n;
198 }
199
200 /* BUG this is O(n^2) to fill in the list */
201 static int
202 convlist(int i, char *a, uint nn)
203 {
204 Conv *c;
205 char buf[512];
206 int n;
207
208 for(c=conv; c && i-- > 0; c=c->next)
209 ;
210
211 if(c == nil)
212 return 0;
213
214 if(c->state)
215 n = snprint(buf, sizeof buf, "conv state=%q %A\n", c->state, c->attr);
216 else
217 n = snprint(buf, sizeof buf, "conv state=closed err=%q\n", c->err);
218
219 if(n >= sizeof(buf)-5)
220 strcpy(buf+sizeof(buf)-5, "...\n");
221 n = strlen(buf);
222 if(n > nn)
223 return 0;
224 memmove(a, buf, n);
225 return n;
226 }
227
228 static void
229 fskickreply(Conv *c)
230 {
231 Req *r;
232
233 if(c->hangup){
234 if((r = c->req) != nil){
235 c->req = nil;
236 respond(r, "hangup");
237 }
238 return;
239 }
240
241 if(!c->req || !c->nreply)
242 return;
243
244 r = c->req;
245 r->ofcall.count = c->nreply;
246 r->ofcall.data = c->reply;
247 if(r->ofcall.count > r->ifcall.count)
248 r->ofcall.count = r->ifcall.count;
249 c->req = nil;
250 respond(r, nil);
251 c->nreply = 0;
252 }
253
254 /*
255 * Some of the file system work happens in the fs proc, but
256 * fsopen, fsread, fswrite, fsdestroyfid, and fsflush happen in
257 * the main proc so that they can access the various shared
258 * data structures without worrying about locking.
259 */
260 static int inuse[nelem(dirtab)];
261 int *confirminuse = &inuse[0];
262 int *needkeyinuse = &inuse[1];
263 static void
264 fsopen(Req *r)
265 {
266 int i, *inusep, perm;
267 static int need[4] = { 4, 2, 6, 1 };
268 Conv *c;
269
270 inusep = nil;
271 perm = 5; /* directory */
272 for(i=0; ifid->qid.path){
274 if(dirtab[i].perm & DMEXCL)
275 inusep = &inuse[i];
276 if(strcmp(r->fid->uid, owner) == 0)
277 perm = dirtab[i].perm>>6;
278 else
279 perm = dirtab[i].perm;
280 break;
281 }
282
283 if((r->ifcall.mode&~(OMASK|OTRUNC))
284 || (need[r->ifcall.mode&3] & ~perm)){
285 respond(r, "permission denied");
286 return;
287 }
288
289 if(inusep){
290 if(*inusep){
291 respond(r, "file in use");
292 return;
293 }
294 *inusep = 1;
295 }
296
297 if(r->fid->qid.path == Qrpc){
298 if((c = convalloc(r->fid->uid)) == nil){
299 char e[ERRMAX];
300
301 rerrstr(e, sizeof e);
302 respond(r, e);
303 return;
304 }
305 c->kickreply = fskickreply;
306 r->fid->aux = c;
307 }
308
309 respond(r, nil);
310 }
311
312 static void
313 fsread(Req *r)
314 {
315 Conv *c;
316
317 switch((int)r->fid->qid.path){
318 default:
319 respond(r, "fsread: cannot happen");
320 break;
321 case Qroot:
322 dirread9p(r, rootdirgen, nil);
323 respond(r, nil);
324 break;
325 case Qfactotum:
326 dirread9p(r, fsdirgen, nil);
327 respond(r, nil);
328 break;
329 case Qrpc:
330 c = r->fid->aux;
331 if(c->rpc.op == RpcUnknown){
332 respond(r, "no rpc pending");
333 break;
334 }
335 if(c->req){
336 respond(r, "read already pending");
337 break;
338 }
339 c->req = r;
340 if(c->nreply)
341 (*c->kickreply)(c);
342 else
343 rpcexec(c);
344 break;
345 case Qconfirm:
346 confirmread(r);
347 break;
348 case Qlog:
349 logread(r);
350 break;
351 case Qctl:
352 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, keylist, r);
353 respond(r, nil);
354 break;
355 case Qneedkey:
356 needkeyread(r);
357 break;
358 case Qprotolist:
359 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, protolist, r);
360 respond(r, nil);
361 break;
362 case Qconv:
363 r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, convlist, r);
364 respond(r, nil);
365 break;
366 }
367 }
368
369 static void
370 fswrite(Req *r)
371 {
372 int ret;
373 char err[ERRMAX], *s;
374 int (*strfn)(char*);
375 char *name;
376
377 switch((int)r->fid->qid.path){
378 default:
379 respond(r, "fswrite: cannot happen");
380 break;
381 case Qrpc:
382 if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
383 rerrstr(err, sizeof err);
384 respond(r, err);
385 }else{
386 r->ofcall.count = r->ifcall.count;
387 respond(r, nil);
388 }
389 break;
390 case Qneedkey:
391 name = "needkey";
392 strfn = needkeywrite;
393 goto string;
394 case Qctl:
395 name = "ctl";
396 strfn = ctlwrite;
397 goto string;
398 case Qconfirm:
399 name = "confirm";
400 strfn = confirmwrite;
401 string:
402 s = emalloc(r->ifcall.count+1);
403 memmove(s, r->ifcall.data, r->ifcall.count);
404 s[r->ifcall.count] = '\0';
405 ret = (*strfn)(s);
406 free(s);
407 if(ret < 0){
408 rerrstr(err, sizeof err);
409 respond(r, err);
410 flog("write %s: %s", name, err);
411 }else{
412 r->ofcall.count = r->ifcall.count;
413 respond(r, nil);
414 }
415 break;
416 }
417 }
418
419 static void
420 fsflush(Req *r)
421 {
422 confirmflush(r->oldreq);
423 logflush(r->oldreq);
424 respond(r, nil);
425 }
426
427 static void
428 fsdestroyfid(Fid *fid)
429 {
430 if(fid->qid.path == Qrpc && fid->aux){
431 convhangup(fid->aux);
432 convclose(fid->aux);
433 }
434 }
435
436 static Channel *creq;
437 static Channel *cfid, *cfidr;
438
439 static void
440 fsreqthread(void *v)
441 {
442 Req *r;
443
444 USED(v);
445
446 while((r = recvp(creq)) != nil){
447 switch(r->ifcall.type){
448 default:
449 respond(r, "bug in fsreqthread");
450 break;
451 case Topen:
452 fsopen(r);
453 break;
454 case Tread:
455 fsread(r);
456 break;
457 case Twrite:
458 fswrite(r);
459 break;
460 case Tflush:
461 fsflush(r);
462 break;
463 }
464 }
465 }
466
467 static void
468 fsclunkthread(void *v)
469 {
470 Fid *f;
471
472 USED(v);
473
474 while((f = recvp(cfid)) != nil){
475 fsdestroyfid(f);
476 sendp(cfidr, 0);
477 }
478 }
479
480 static void
481 fsproc(void *v)
482 {
483 USED(v);
484
485 threadcreate(fsreqthread, nil, STACK);
486 threadcreate(fsclunkthread, nil, STACK);
487 threadexits(nil);
488 }
489
490 static void
491 fsattach(Req *r)
492 {
493 r->fid->qid = mkqid(QTDIR, qtop);
494 r->ofcall.qid = r->fid->qid;
495 respond(r, nil);
496 }
497
498 static void
499 fssend(Req *r)
500 {
501 sendp(creq, r);
502 }
503
504 static void
505 fssendclunk(Fid *f)
506 {
507 sendp(cfid, f);
508 recvp(cfidr);
509 }
510
511 void
512 fsstart(Srv *s)
513 {
514 USED(s);
515
516 if(extrafactotumdir)
517 qtop = Qroot;
518 else
519 qtop = Qfactotum;
520 creq = chancreate(sizeof(Req*), 0);
521 cfid = chancreate(sizeof(Fid*), 0);
522 cfidr = chancreate(sizeof(Fid*), 0);
523 proccreate(fsproc, nil, STACK);
524 }
525
526 Srv fs;
527
528 void
529 fsinit0(void)
530 {
531 fs.attach = fsattach;
532 fs.walk1 = fswalk1;
533 fs.open = fssend;
534 fs.read = fssend;
535 fs.write = fssend;
536 fs.stat = fsstat;
537 fs.flush = fssend;
538 fs.destroyfid = fssendclunk;
539 fs.start = fsstart;
540 } |