diff options
Diffstat (limited to 'appl/cmd/vacget.b')
| -rw-r--r-- | appl/cmd/vacget.b | 199 |
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); +} |
