changelog shortlog tags branches changeset files revisions annotate raw help

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

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