summaryrefslogtreecommitdiff
path: root/appl/cmd/vacget.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/vacget.b')
-rw-r--r--appl/cmd/vacget.b199
1 files changed, 199 insertions, 0 deletions
diff --git a/appl/cmd/vacget.b b/appl/cmd/vacget.b
new file mode 100644
index 00000000..c14ad28a
--- /dev/null
+++ b/appl/cmd/vacget.b
@@ -0,0 +1,199 @@
+implement Vacget;
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+include "arg.m";
+include "string.m";
+include "venti.m";
+include "vac.m";
+
+str: String;
+venti: Venti;
+vac: Vac;
+
+print, sprint, fprint, fildes: import sys;
+Score, Session: import venti;
+Roottype, Dirtype, Pointertype0, Datatype: import venti;
+Root, Entry, Direntry, Metablock, Metaentry, Entrysize, Modeperm, Modeappend, Modeexcl, Modedir, Modesnapshot, Vacdir, Vacfile, Source: import vac;
+
+Vacget: module {
+ init: fn(nil: ref Draw->Context, args: list of string);
+};
+
+addr := "net!$venti!venti";
+dflag := vflag := pflag := tflag := 0;
+session: ref Session;
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ arg := load Arg Arg->PATH;
+ str = load String String->PATH;
+ venti = load Venti Venti->PATH;
+ vac = load Vac Vac->PATH;
+ if(venti == nil || vac == nil)
+ error("loading venti,vac");
+ venti->init();
+ vac->init();
+
+ arg->init(args);
+ arg->setusage(sprint("%s [-dtv] [-a addr] [tag:]score", arg->progname()));
+ while((c := arg->opt()) != 0)
+ case c {
+ 'a' => addr = arg->earg();
+ 'd' => dflag++;
+ vac->dflag++;
+ 'p' => pflag++;
+ 't' => tflag++;
+ 'v' => vflag++;
+ * => warn(sprint("bad option: -%c", c));
+ arg->usage();
+ }
+ args = arg->argv();
+ if(len args != 1)
+ arg->usage();
+
+ (tag, scorestr) := str->splitstrr(hd args, ":");
+ if(tag != nil)
+ tag = tag[:len tag-1];
+ if(tag == nil)
+ tag = "vac";
+ if(tag != "vac")
+ error("bad score type: "+tag);
+
+ (sok, score) := Score.parse(scorestr);
+ if(sok != 0)
+ error("bad score: "+scorestr);
+ say("have score");
+
+ (cok, conn) := sys->dial(addr, nil);
+ if(cok < 0)
+ error(sprint("dialing %s: %r", addr));
+ say("have connection");
+
+ fd := conn.dfd;
+ session = Session.new(fd);
+ if(session == nil)
+ error(sprint("handshake: %r"));
+ say("have handshake");
+
+ (vd, nil, err) := vac->vdroot(session, score);
+ if(err != nil)
+ error(err);
+
+ say("starting walk");
+ walk(".", vd);
+}
+
+create(path: string, omode: int, de: ref Direntry): ref Sys->FD
+{
+ perm := Sys->DMDIR | Sys->DMAPPEND | Sys->DMEXCL | Sys->DMTMP;
+ perm &= de.emode;
+ perm |= 8r666;
+ if(de.emode & Sys->DMDIR)
+ perm |= 8r777;
+ fd := sys->create(path, omode, perm);
+ if(fd == nil)
+ return nil;
+ if(pflag) {
+ d := sys->nulldir;
+ d.uid = de.uid;
+ d.gid = de.gid;
+ d.mode = de.emode;
+ if(sys->fwstat(fd, d) != 0) {
+ warn(sprint("fwstat %s for uid/gid/mode: %r", path));
+ d.uid = d.gid = "";
+ sys->fwstat(fd, d);
+ }
+ }
+ return fd;
+}
+
+walk(path: string, vd: ref Vacdir)
+{
+ say("start of walk: "+path);
+ for(;;) {
+ (n, de) := vd.readdir();
+ if(n < 0)
+ error(sprint("reading direntry in %s: %r", path));
+ if(n == 0)
+ break;
+ say("walk: have direntry, elem="+de.elem);
+ newpath := path+"/"+de.elem;
+ (e, me) := vd.open(de);
+ if(e == nil)
+ error(sprint("reading entry for %s: %r", newpath));
+
+ oflags := de.mode&~(Modeperm|Modeappend|Modeexcl|Modedir|Modesnapshot);
+ if(oflags)
+ warn(sprint("%s: not all bits in mode can be set: 0x%x", newpath, oflags));
+
+ if(tflag || vflag)
+ print("%s\n", newpath);
+
+ if(me != nil) {
+ if(!tflag)
+ create(newpath, Sys->OREAD, de);
+ # ignore error, possibly for already existing dir.
+ # if creating really failed, writing files in the dir will fail later on.
+ walk(newpath, Vacdir.new(session, e, me));
+ } else {
+ if(tflag)
+ continue;
+ say("writing file");
+ fd := create(newpath, sys->OWRITE, de);
+ if(fd == nil)
+ error(sprint("creating %s: %r", newpath));
+ bio := bufio->fopen(fd, bufio->OWRITE);
+ if(bio == nil)
+ error(sprint("bufio fopen %s: %r", newpath));
+
+ buf := array[sys->ATOMICIO] of byte;
+ vf := Vacfile.new(session, e);
+ for(;;) {
+ rn := vf.read(buf, len buf);
+ if(rn == 0)
+ break;
+ if(rn < 0)
+ error(sprint("reading vac %s: %r", newpath));
+ wn := bio.write(buf, rn);
+ if(wn != rn)
+ error(sprint("writing local %s: %r", newpath));
+ }
+ bok := bio.flush();
+ bio.close();
+ if(bok == bufio->ERROR || bok == bufio->EOF)
+ error(sprint("bufio close: %r"));
+
+ if(pflag) {
+ d := sys->nulldir;
+ d.mtime = de.mtime;
+ if(sys->fwstat(fd, d) < 0)
+ warn(sprint("fwstat %s for mtime: %r", newpath));
+ }
+ fd = nil;
+ }
+ }
+}
+
+error(s: string)
+{
+ fprint(fildes(2), "%s\n", s);
+ raise "fail:"+s;
+}
+
+warn(s: string)
+{
+ fprint(fildes(2), "%s\n", s);
+}
+
+say(s: string)
+{
+ if(dflag)
+ warn(s);
+}