changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > ventivac / appl/cmd/vacfs.b

changeset 104: bd9330e95ebb
parent: c6c061169cb7
child: b2d15be09468
author: Mechiel Lukkien <mechiel@ueber.net>
date: Wed, 15 Aug 2007 18:02:32 +0200
permissions: -rw-r--r--
description: minor changes. do not kill processes, just send nil over channel. do not pctl pgrp.
1 implement Vacfs;
2 
3 include "sys.m";
4  sys: Sys;
5 include "draw.m";
6 include "arg.m";
7 include "string.m";
8 include "daytime.m";
9 include "venti.m";
10 include "vac.m";
11 include "styx.m";
12  styx: Styx;
13  Tmsg, Rmsg: import styx;
14 include "styxservers.m";
15 
16 str: String;
17 daytime: Daytime;
18 venti: Venti;
19 vac: Vac;
20 styxservers: Styxservers;
21 
22 print, sprint, fprint, fildes: import sys;
23 Score, Session: import venti;
24 Direntry, Vacdir, Vacfile, Source: import vac;
25 Styxserver, Fid, Navigator, Navop, Enotfound: import styxservers;
26 
27 Vacfs: module {
28  init: fn(nil: ref Draw->Context, args: list of string);
29 };
30 
31 addr := "net!$venti!venti";
32 dflag := pflag := 0;
33 session: ref Session;
34 
35 srv: ref Styxserver;
36 
37 Elem: adt {
38  qid: int;
39  de: ref Direntry;
40  size: big;
41  nused: int;
42  pick {
43  File => vf: ref Vacfile;
44  Dir => vd: ref Vacdir;
45  pqid: int;
46  prev: (int, ref Sys->Dir);
47  }
48 
49  mkdir: fn(qid: int, de: ref Direntry, size: big, vd: ref Vacdir, pqid: int): ref Elem.Dir;
50  new: fn(nqid: int, vd: ref Vacdir, de: ref Direntry, pqid: int): ref Elem;
51  stat: fn(e: self ref Elem): ref Sys->Dir;
52 };
53 
54 Qdir: adt {
55  qid: int;
56  cqids: list of (big, int);
57 };
58 
59 elems := array[512] of list of ref Elem;
60 qids := array[512] of list of ref Qdir;
61 lastqid := 0;
62 qidscores: list of (string, int);
63 
64 
65 childget(qid: int, vqid: big): int
66 {
67  for(l := qids[qid % len qids]; l != nil; l = tl l) {
68  if((hd l).qid != qid)
69  continue;
70  for(m := (hd l).cqids; m != nil; m = tl m) {
71  (vq, cq) := hd m;
72  if(vq == vqid)
73  return cq;
74  }
75  }
76  return -1;
77 }
78 
79 childput(qid: int, vqid: big): int
80 {
81  qd: ref Qdir;
82  for(l := qids[qid % len qids]; l != nil; l = tl l)
83  if((hd l).qid == qid) {
84  qd = hd l;
85  break;
86  }
87  if(qd == nil) {
88  qd = ref Qdir(qid, nil);
89  qids[qid % len qids] = qd::nil;
90  }
91  qd.cqids = (vqid, ++lastqid)::qd.cqids;
92  return lastqid;
93 }
94 
95 scoreget(score: string): ref Elem
96 {
97  for(l := qidscores; l != nil; l = tl l) {
98  (s, n) := hd l;
99  if(s == score)
100  return get(n);
101  }
102  return nil;
103 }
104 
105 scoreput(score: string): int
106 {
107  qidscores = (score, ++lastqid)::qidscores;
108  return lastqid;
109 }
110 
111 Elem.mkdir(qid: int, de: ref Direntry, size: big, vd: ref Vacdir, pqid: int): ref Elem.Dir
112 {
113  return ref Elem.Dir(qid, de, size, 0, vd, pqid, (-1, nil));
114 }
115 
116 Elem.new(nqid: int, vd: ref Vacdir, de: ref Direntry, pqid: int): ref Elem
117 {
118  (e, me) := vd.open(de);
119  if(e == nil)
120  return nil;
121  if(de.mode & Vac->Modedir)
122  return Elem.mkdir(nqid, de, e.size, Vacdir.new(session, e, me), pqid);
123  return ref Elem.File(nqid, de, e.size, 0, Vacfile.new(session, e));
124 }
125 
126 Elem.stat(e: self ref Elem): ref Sys->Dir
127 {
128  d := e.de.mkdir();
129  d.qid.path = big e.qid;
130  d.length = e.size;
131  return d;
132 }
133 
134 walk(ed: ref Elem.Dir, name: string): (ref Elem, string)
135 {
136  if(name == "..")
137  return (get(ed.pqid), nil);
138 
139  if(ed.qid == 0) {
140  ne := scoreget(name);
141  if(ne == nil) {
142  (ok, score) := Score.parse(name);
143  if(ok != 0)
144  return (nil, "bad score");
145 
146  (vd, de, err) := vac->vdroot(session, score);
147  if(err != nil)
148  return (nil, err);
149 
150  nqid := scoreput(name);
151  ne = Elem.mkdir(nqid, de, big 0, vd, ed.qid);
152  set(ne);
153  }
154  return (ne, nil);
155  }
156 
157  de := ed.vd.walk(name);
158  if(de == nil)
159  return (nil, sprint("%r"));
160  cqid := childget(ed.qid, de.qid);
161  ne: ref Elem;
162  if(cqid < 0)
163  cqid = childput(ed.qid, de.qid);
164  else
165  ne = get(cqid);
166  if(ne == nil) {
167  ne = Elem.new(cqid, ed.vd, de, ed.qid);
168  set(ne);
169  }
170  return (ne, nil);
171 }
172 
173 get(qid: int): ref Elem
174 {
175  for(l := elems[qid % len elems]; l != nil; l = tl l)
176  if((hd l).qid == qid)
177  return hd l;
178  return nil;
179 }
180 
181 set(e: ref Elem)
182 {
183  elems[e.qid % len elems] = e::elems[e.qid % len elems];
184 }
185 
186 remove[T](l: list of T, e: T): list of T
187 {
188  r: list of T;
189  for(; l != nil; l = tl l)
190  if(hd l != e)
191  r = hd l::r;
192  return r;
193 }
194 
195 del(e: ref Elem)
196 {
197  i := e.qid % len elems;
198  elems[i] = remove(elems[i], e);
199 }
200 
201 getfile(qid: int): ref Elem.File
202 {
203  pick file := get(qid) {
204  File => return file;
205  }
206  error("internal error, getfile");
207  return nil;
208 }
209 
210 getdir(qid: int): ref Elem.Dir
211 {
212  pick d := get(qid) {
213  Dir => return d;
214  }
215  error("internal error, getdir");
216  return nil;
217 }
218 
219 init(nil: ref Draw->Context, args: list of string)
220 {
221  sys = load Sys Sys->PATH;
222  arg := load Arg Arg->PATH;
223  str = load String String->PATH;
224  daytime = load Daytime Daytime->PATH;
225  venti = load Venti Venti->PATH;
226  styx = load Styx Styx->PATH;
227  styxservers = load Styxservers Styxservers->PATH;
228  vac = load Vac Vac->PATH;
229 
230  venti->init();
231  vac->init();
232  styx->init();
233  styxservers->init(styx);
234 
235  arg->init(args);
236  arg->setusage(arg->progname()+" [-Ddp] [-a addr] [vacfile]");
237  while((ch := arg->opt()) != 0)
238  case ch {
239  'D' => styxservers->traceset(1);
240  'a' => addr = arg->earg();
241  'd' => dflag++;
242  vac->dflag++;
243  'p' => pflag++;
244  * => arg->usage();
245  }
246  args = arg->argv();
247  if(len args > 1)
248  arg->usage();
249 
250  score: ref Score;
251  if(len args == 1) {
252  err: string;
253  (nil, score, err) = vac->readscore(hd args);
254  if(err != nil)
255  error("reading score: "+err);
256  }
257 
258  (cok, conn) := sys->dial(addr, nil);
259  if(cok < 0)
260  error(sprint("dialing %s: %r", addr));
261  say("have connection");
262 
263  session = Session.new(conn.dfd);
264  if(session == nil)
265  error(sprint("handshake: %r"));
266  say("have handshake");
267 
268  rqid := 0;
269  red: ref Elem;
270  if(args == nil) {
271  de := Direntry.new();
272  de.uid = de.gid = de.mid = "vacfs";
273  de.ctime = de.atime = de.mtime = daytime->now();
274  de.mode = Vac->Modedir|8r555;
275  de.emode = Sys->DMDIR|8r555;
276  red = Elem.mkdir(rqid, de, big 0, nil, rqid);
277  } else {
278  (vd, de, err) := vac->vdroot(session, *score);
279  if(err != nil)
280  error(err);
281  rqid = ++lastqid;
282  red = Elem.mkdir(rqid, de, big 0, vd, rqid);
283  }
284  set(red);
285  say(sprint("have root, qid=%d", rqid));
286 
287  navchan := chan of ref Navop;
288  nav := Navigator.new(navchan);
289  spawn navigator(navchan);
290 
291  msgc: chan of ref Tmsg;
292  (msgc, srv) = Styxserver.new(sys->fildes(0), nav, big rqid);
293 
294 serve:
295  while((mm := <-msgc) != nil)
296  pick m := mm {
297  Readerror =>
298  fprint(fildes(2), "styx read: %s\n", m.error);
299  break serve;
300 
301  Read =>
302  say(sprint("have read, offset=%ubd count=%d", m.offset, m.count));
303  (c, err) := srv.canread(m);
304  if(c == nil){
305  srv.reply(ref Rmsg.Error(m.tag, err));
306  continue;
307  }
308  if(c.qtype & Sys->QTDIR){
309  srv.default(m);
310  continue;
311  }
312 
313  ef := getfile(int c.path);
314  n := m.count;
315  a := array[n] of byte;
316  have := ef.vf.pread(a, n, m.offset);
317  if(have < 0) {
318  srv.reply(ref Rmsg.Error(m.tag, sprint("%r")));
319  continue;
320  }
321  srv.reply(ref Rmsg.Read(m.tag, a[:have]));
322 
323  Open =>
324  (c, mode, f, err) := canopen(m);
325  if(c == nil){
326  srv.reply(ref Rmsg.Error(m.tag, err));
327  continue;
328  }
329  c.open(mode, f.qid);
330  srv.reply(ref Rmsg.Open(m.tag, f.qid, srv.iounit()));
331 
332  Clunk =>
333  f := srv.getfid(m.fid);
334  if(f != nil) {
335  pick e := get(int f.path) {
336  Dir =>
337  if(e.pqid != 0 && --e.nused <= 0)
338  del(e);
339  File =>
340  if(--e.nused <= 0)
341  del(e);
342  }
343  }
344  srv.default(m);
345 
346  * =>
347  srv.default(m);
348  }
349  navchan <-= nil;
350 }
351 
352 # from appl/lib/styxservers.b
353 canopen(m: ref Tmsg.Open): (ref Fid, int, ref Sys->Dir, string)
354 {
355  c := srv.getfid(m.fid);
356  if(c == nil)
357  return (nil, 0, nil, Styxservers->Ebadfid);
358  if(c.isopen)
359  return (nil, 0, nil, Styxservers->Eopen);
360  (f, err) := srv.t.stat(c.path);
361  if(f == nil)
362  return (nil, 0, nil, err);
363  mode := styxservers->openmode(m.mode);
364  if(mode == -1)
365  return (nil, 0, nil, Styxservers->Ebadarg);
366  if(mode != Sys->OREAD && f.qid.qtype & Sys->QTDIR)
367  return (nil, 0, nil, Styxservers->Eperm);
368  if(!pflag && !styxservers->openok(c.uname, m.mode, f.mode, f.uid, f.gid))
369  return (nil, 0, nil, Styxservers->Eperm);
370  if(m.mode & Sys->ORCLOSE)
371  return (nil, 0, nil, Styxservers->Eperm);
372  return (c, mode, f, err);
373 }
374 
375 navigator(c: chan of ref Navop)
376 {
377  while((navop := <-c) != nil)
378  pick n := navop {
379  Stat =>
380  n.reply <-= (get(int n.path).stat(), nil);
381 
382  Walk =>
383  ed := getdir(int n.path);
384  (ne, err) := walk(ed, n.name);
385  if(err != nil) {
386  n.reply <-= (nil, err);
387  continue;
388  }
389  ed.nused--;
390  ne.nused++;
391  n.reply <-= (ne.stat(), nil);
392 
393  Readdir =>
394  if(dflag) say(sprint("have readdir path=%bd offset=%d count=%d", n.path, n.offset, n.count));
395  if(n.path == big 0) {
396  n.reply <-= (nil, nil);
397  continue;
398  }
399  ed := getdir(int n.path);
400  if(n.offset == 0) {
401  ed.vd.rewind();
402  ed.prev = (-1, nil);
403  }
404 
405  (loffset, d) := ed.prev;
406  if(loffset != n.offset) {
407  (ok, de) := ed.vd.readdir();
408  if(ok < 0) {
409  say(sprint("readdir error: %r"));
410  n.reply <-= (nil, sprint("reading directory: %r"));
411  continue;
412  }
413  if(de != nil) {
414  cqid := childget(ed.qid, de.qid);
415  if(cqid < 0)
416  cqid = childput(ed.qid, de.qid);
417  ne := get(cqid);
418  if(ne == nil)
419  ne = Elem.new(cqid, ed.vd, de, ed.qid);
420  if(dflag) say(sprint("readdir, childget(%d, %bd) = %d", ed.qid, de.qid, ne.qid));
421  ed.prev = (n.offset, ne.stat());
422  } else {
423  ed.prev = (n.offset, nil);
424  }
425  }
426  (nil, d) = ed.prev;
427  if(d != nil)
428  n.reply <-= (d, nil);
429  n.reply <-= (nil, nil);
430  }
431 }
432 
433 error(s: string)
434 {
435  fprint(fildes(2), "%s\n", s);
436  raise "fail:"+s;
437 }
438 
439 say(s: string)
440 {
441  if(dflag)
442  fprint(fildes(2), "%s\n", s);
443 }