ref: d0ab3a0dd8f6355b3603d0fb04043a9ae867639b
dir: /appl/cmd/vacget.b/
implement Vacget;
include "sys.m";
sys: Sys;
sprint: import sys;
include "draw.m";
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "arg.m";
include "dial.m";
dial: Dial;
include "string.m";
str: String;
include "venti.m";
venti: Venti;
Root, Entry, Score, Session: import venti;
include "vac.m";
vac: Vac;
Direntry, Vacdir, Vacfile: import vac;
Vacget: module {
init: fn(nil: ref Draw->Context, args: list of string);
};
addr := "$venti";
dflag: int;
vflag: int;
pflag: int;
tflag: int;
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;
dial = load Dial Dial->PATH;
str = load String String->PATH;
venti = load Venti Venti->PATH;
vac = load Vac Vac->PATH;
if(venti == nil || vac == nil)
fail("loading venti,vac");
venti->init();
vac->init();
arg->init(args);
arg->setusage(arg->progname()+" [-dtv] [-a addr] [tag:]score");
while((c := arg->opt()) != 0)
case c {
'a' => addr = arg->earg();
'd' => vac->dflag = dflag++;
'p' => pflag++;
't' => tflag++;
'v' => vflag++;
* => 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")
fail("bad score type: "+tag);
(sok, score) := Score.parse(scorestr);
if(sok != 0)
fail("bad score: "+scorestr);
say("have score");
addr = dial->netmkaddr(addr, "net", "venti");
cc := dial->dial(addr, nil);
if(cc == nil)
fail(sprint("dialing %s: %r", addr));
say("have connection");
fd := cc.dfd;
session = Session.new(fd);
if(session == nil)
fail(sprint("handshake: %r"));
say("have handshake");
(vd, nil, err) := vac->vdroot(session, score);
if(err != nil)
fail(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)
fail(sprint("reading direntry in %s: %r", path));
if(n == 0)
break;
if(dflag) say("walk: have direntry, elem="+de.elem);
newpath := path+"/"+de.elem;
(e, me) := vd.open(de);
if(e == nil)
fail(sprint("reading entry for %s: %r", newpath));
oflags := de.mode&~(vac->Modeperm|vac->Modeappend|vac->Modeexcl|vac->Modedir|vac->Modesnapshot);
if(oflags)
warn(sprint("%s: not all bits in mode can be set: 0x%x", newpath, oflags));
if(tflag || vflag)
sys->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)
fail(sprint("creating %s: %r", newpath));
bio := bufio->fopen(fd, bufio->OWRITE);
if(bio == nil)
fail(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)
fail(sprint("reading vac %s: %r", newpath));
wn := bio.write(buf, rn);
if(wn != rn)
fail(sprint("writing local %s: %r", newpath));
}
bok := bio.flush();
bio.close();
if(bok == bufio->ERROR || bok == bufio->EOF)
fail(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;
}
}
}
say(s: string)
{
if(dflag)
warn(s);
}
fd2: ref Sys->FD;
warn(s: string)
{
if(fd2 == nil)
fd2 = sys->fildes(2);
sys->fprint(fd2, "%s\n", s);
}
fail(s: string)
{
warn(s);
raise "fail:"+s;
}