changelog shortlog tags branches changeset files revisions annotate raw help

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

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