changelog shortlog tags branches changeset files revisions annotate raw help

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

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