changelog shortlog tags branches changeset files revisions annotate raw help

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

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