changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 121: 7fd24f62e50a
parent: c6c061169cb7
child: 84abb5444a76
author: Mechiel Lukkien <mechiel@ueber.net>
date: Fri, 17 Aug 2007 22:25:28 +0200
permissions: -rw-r--r--
description: move default rabin parameters to vac.m
1 implement Vacput;
2 
3 include "sys.m";
4  sys: Sys;
5 include "draw.m";
6 include "daytime.m";
7 include "bufio.m";
8  bufio: Bufio;
9  Iobuf: import bufio;
10 include "arg.m";
11 include "string.m";
12 include "venti.m";
13 include "vac.m";
14 include "rabin.m";
15 
16 daytime: Daytime;
17 str: String;
18 venti: Venti;
19 vac: Vac;
20 rabin: Rabin;
21 
22 print, sprint, fprint, fildes: import sys;
23 Score, Session: import venti;
24 Rootversion, Roottype, Dirtype, Datatype, Rootsize: import venti;
25 Rootversionvar, Root, Entry, Direntry, Entrysize, File, Sink, MSink, Vacdir: import vac;
26 Rcfg, Rfile: import rabin;
27 
28 Vacput: module {
29  init: fn(nil: ref Draw->Context, args: list of string);
30 };
31 
32 addr := "net!$venti!venti";
33 Dflag, vflag, qflag, rflag: int;
34 blocksize := vac->Dsize;
35 session: ref Session;
36 name := "vac";
37 basescore: ref Score;
38 rcfg: ref Rcfg;
39 blockmin, blockmax: int;
40 
41 init(nil: ref Draw->Context, args: list of string)
42 {
43  sys = load Sys Sys->PATH;
44  daytime = load Daytime Daytime->PATH;
45  bufio = load Bufio Bufio->PATH;
46  arg := load Arg Arg->PATH;
47  str = load String String->PATH;
48  venti = load Venti Venti->PATH;
49  vac = load Vac Vac->PATH;
50  rabin = load Rabin Rabin->PATH;
51 
52  venti->init();
53  vac->init();
54  rabin->init(bufio);
55 
56  prime := Vac->Rabinprime;
57  mod := Vac->Rabinmod;
58  width := Vac->Rabinwidth;
59  blockmin = Vac->Rabinblockmin;
60  blockmax = Vac->Rabinblockmax;
61 
62  arg->init(args);
63  arg->setusage(sprint("%s [-Dqrv] [-d vacfile] [-a addr] [-b blocksize] [-n name] path ...", arg->progname()));
64  while((c := arg->opt()) != 0)
65  case c {
66  'a' => addr = arg->earg();
67  'b' => blocksize = int arg->earg();
68  'n' => name = arg->earg();
69  'd' =>
70  err: string;
71  (nil, basescore, err) = vac->readscore(arg->earg());
72  if(err != nil)
73  error("reading score: "+err);
74  'D' => Dflag++;
75  vac->dflag++;
76  rabin->debug++;
77  vflag++;
78  'q' => qflag++;
79  'r' => rflag++;
80  'v' => vflag++;
81  * => arg->usage();
82  }
83  args = arg->argv();
84  if(len args == 0)
85  arg->usage();
86 
87  if(rflag) {
88  err: string;
89  (rcfg, err) = Rcfg.mk(prime, width, mod);
90  if(err != nil)
91  error("rabincfg: "+err);
92  }
93 
94  (cok, conn) := sys->dial(addr, nil);
95  if(cok < 0)
96  error(sprint("dialing %s: %r", addr));
97  say("have connection");
98 
99  fd := conn.dfd;
100  session = Session.new(fd);
101  if(session == nil)
102  error(sprint("handshake: %r"));
103  say("have handshake");
104 
105  vd: ref Vacdir;
106  if(basescore != nil) {
107  err: string;
108  (vd, nil, err) = vac->vdroot(session, *basescore);
109  if(err != nil)
110  error("opening base score: "+err);
111 
112  d := session.read(*basescore, Roottype, Rootsize);
113  if(d == nil)
114  error("reading base root block: "+err);
115  r := Root.unpack(d);
116  if(rflag && r.version != Rootversionvar || !rflag && r.version != Rootversion)
117  error("old archive not of same type as new archive");
118  }
119 
120  topde: ref Direntry;
121  if(len args == 1 && ((nil, d) := sys->stat(hd args)).t0 == 0 && d.mode&Sys->DMDIR) {
122  topde = Direntry.mk(d);
123  topde.elem = name;
124  } else {
125  topde = Direntry.new();
126  topde.elem = name;
127  topde.uid = topde.gid = user();
128  topde.mode = 8r777|Vac->Modedir;
129  topde.mtime = topde.atime = 0;
130  }
131  topde.ctime = daytime->now();
132 
133  s := Sink.new(session, blocksize);
134  ms := MSink.new(session, blocksize);
135  for(; args != nil; args = tl args)
136  writepath(hd args, s, ms, vd);
137  say("tree written");
138 
139  e0 := s.finish();
140  if(e0 == nil)
141  error(sprint("writing top entry: %r"));
142  e1 := ms.finish();
143  if(e1 == nil)
144  error(sprint("writing top meta entry: %r"));
145  say(sprint("top entries written (%s, %s)", e0.score.text(), e1.score.text()));
146  s2 := MSink.new(session, blocksize);
147  if(s2.add(topde) < 0)
148  error(sprint("adding direntry for top entries: %r"));
149  e2 := s2.finish();
150  say("top meta entry written, "+e2.score.text());
151 
152  td := array[Entrysize*3] of byte;
153  td[0*Entrysize:] = e0.pack();
154  td[1*Entrysize:] = e1.pack();
155  td[2*Entrysize:] = e2.pack();
156  (tok, tscore) := session.write(Dirtype, td);
157  if(tok < 0)
158  error(sprint("writing top-level entries: %r"));
159  say("top entry written, "+tscore.text());
160 
161  root := Root.new(name, "vac", tscore, blocksize, nil);
162  if(rflag) {
163  root.version = Vac->Rootversionvar;
164  root.blocksize = 0;
165  }
166  if(basescore != nil)
167  root.prev = basescore;
168  rd := root.pack();
169  if(rd == nil)
170  error(sprint("root pack: %r"));
171  (rok, rscore) := session.write(Roottype, rd);
172  if(rok < 0)
173  error(sprint("writing root score: %r"));
174 
175  if(session.sync() < 0)
176  error(sprint("syncing server: %r"));
177 
178  say("root written, "+rscore.text());
179  print("%s:%s\n", root.rtype, rscore.text());
180  if(vflag) {
181  fprint(fildes(2), "%10bd %13bd blocks read/written\n", vac->blocksread, vac->blockswritten);
182  fprint(fildes(2), "%10bd %13bd bytes read/written\n", vac->bytesread, vac->byteswritten);
183  }
184 }
185 
186 writepath(path: string, s: ref Sink, ms: ref MSink, vd: ref Vacdir)
187 {
188  if(vflag)
189  fprint(fildes(2), "%s\n", path);
190 say("writepath "+path);
191  fd := sys->open(path, sys->OREAD);
192  if(fd == nil)
193  error(sprint("opening %s: %r", path));
194  (ok, dir) := sys->fstat(fd);
195  if(ok < 0)
196  error(sprint("fstat %s: %r", path));
197 say("writepath: file opened");
198  if(dir.mode&sys->DMAUTH) {
199  fprint(fildes(2), "%s: is auth file, skipping", path);
200  return;
201  }
202  if(dir.mode&sys->DMTMP) {
203  fprint(fildes(2), "%s: is temporary file, skipping", path);
204  return;
205  }
206 
207  e, me: ref Entry;
208  de: ref Direntry;
209  if(dir.mode & sys->DMDIR) {
210 say("writepath: file is dir");
211  ns := Sink.new(session, blocksize);
212  nms := MSink.new(session, blocksize);
213 
214  nvd := vdopendir(vd, dir.name);
215  for(;;) {
216  (n, dirs) := sys->dirread(fd);
217  if(n == 0)
218  break;
219  if(n < 0)
220  error(sprint("dirread %s: %r", path));
221  for(i := 0; i < len dirs; i++) {
222  d := dirs[i];
223  npath := path+"/"+d.name;
224  writepath(npath, ns, nms, nvd);
225  }
226  }
227  e = ns.finish();
228  if(e == nil)
229  error(sprint("error flushing dirsink for %s: %r", path));
230  me = nms.finish();
231  if(me == nil)
232  error(sprint("error flushing metasink for %s: %r", path));
233  } else {
234 say("writepath: file is normal file");
235  nde: ref Direntry;
236  if(vd != nil)
237  nde = vd.walk(dir.name);
238  if(nde != nil)
239  (e, nil) = vd.open(nde);
240  f: ref File;
241  offset := big 0;
242  if(e != nil && qflag
243  && (nde.mode&Vac->Modeappend)
244  && (dir.mode&Sys->DMAPPEND)
245  && nde.mtime < dir.mtime
246  && e.size < dir.length
247  && nde.qid == dir.qid.path
248  && nde.mcount < dir.qid.vers)
249  {
250  f = File.mkstate(session, e, rflag);
251  offset = f.size;
252  } else if(f == nil && e != nil
253  && (nde.mtime != dir.mtime
254  || e.size != dir.length
255  || nde.qid != dir.qid.path
256  || nde.mcount != dir.qid.vers))
257  e = nil;
258  if(f == nil && e == nil)
259  f = File.new(session, Datatype, blocksize, rflag);
260 
261  if(f != nil) {
262 say("writepath: file has changed or is new, writing it");
263  e = writefile(path, fd, f, offset);
264  if(e == nil)
265  error(sprint("error flushing filesink for %s: %r", path));
266  }
267  }
268 say("writepath: wrote path, "+e.score.text());
269 
270  de = Direntry.mk(dir);
271 say("writepath: have direntry");
272 
273  i := s.add(e);
274  if(i < 0)
275  error(sprint("adding entry to sink: %r"));
276  mi := 0;
277  if(me != nil)
278  mi = s.add(me);
279  if(mi < 0)
280  error(sprint("adding mentry to sink: %r"));
281  de.entry = i;
282  de.mentry = mi;
283  i = ms.add(de);
284  if(i < 0)
285  error(sprint("adding direntry to msink: %r"));
286 say("writepath done");
287 }
288 
289 writefile(path: string, fd: ref Sys->FD, f: ref File, offset: big): ref Entry
290 {
291  bio := bufio->fopen(fd, bufio->OREAD);
292  if(bio == nil)
293  error(sprint("bufio opening %s: %r", path));
294  say(sprint("bufio opened path %s, offset=%bd", path, offset));
295  bio.seek(offset, Bufio->SEEKSTART);
296 
297  rfile: ref Rfile;
298  if(rflag) {
299  err: string;
300  (rfile, err) = rabin->open(rcfg, bio, blockmin, blockmax);
301  if(err != nil)
302  error(sprint("rabin open %s: %s", path, err));
303  }
304 
305  for(;;) {
306  if(rflag) {
307  (d, nil, err) := rfile.read();
308  if(err != nil)
309  error(sprint("reading %s: %s", path, err));
310  if(len d == 0)
311  break;
312  if(f.write(d) < 0)
313  error(sprint("writing %s: %r", path));
314  } else {
315  buf := array[blocksize] of byte;
316  n := 0;
317  while(n < len buf) {
318  want := len buf - n;
319  have := bio.read(buf[n:], want);
320  if(have == 0)
321  break;
322  if(have < 0)
323  error(sprint("reading %s: %r", path));
324  n += have;
325  }
326  say(sprint("have buf, length %d", n));
327 
328  if(f.write(buf[:n]) < 0)
329  error(sprint("writing %s: %r", path));
330  if(n != len buf)
331  break;
332  }
333  }
334  bio.close();
335  return f.finish();
336 }
337 
338 vdopendir(vd: ref Vacdir, elem: string): ref Vacdir
339 {
340  if(vd == nil)
341  return nil;
342  de := vd.walk(elem);
343  if(de == nil)
344  return nil;
345  (e, me) := vd.open(de);
346  if(e == nil || me == nil)
347  return nil;
348  return Vacdir.new(session, e, me);
349 }
350 
351 user(): string
352 {
353  if((fd := sys->open("/dev/user", Sys->OREAD)) != nil
354  && (n := sys->read(fd, d := array[128] of byte, len d)) > 0)
355  return string d[:n];
356  return "nobody";
357 }
358 
359 error(s: string)
360 {
361  fprint(fildes(2), "%s\n", s);
362  raise "fail:"+s;
363 }
364 
365 say(s: string)
366 {
367  if(Dflag)
368  fprint(fildes(2), "%s\n", s);
369 }