implement Vacput; include "sys.m"; sys: Sys;include "draw.m";include "daytime.m";include "bufio.m"; bufio: Bufio; Iobuf: import bufio;include "arg.m";include "string.m";include "venti.m";include "vac.m"; daytime: Daytime;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, File, Sink, MSink: import vac; Vacput: module { init: fn(nil: ref Draw->Context, args: list of string);}; addr := "net!$venti!venti";dflag := 0;vflag := 0;blocksize := vac->Dsize;session: ref Session;name := "vac"; init(nil: ref Draw->Context, args: list of string){ sys = load Sys Sys->PATH; daytime = load Daytime Daytime->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] [-b blocksize] [-n name] path ...", arg->progname())); while((c := arg->opt()) != 0) case c { 'a' => addr = arg->earg(); 'b' => blocksize = int arg->earg(); 'n' => name = arg->earg(); 'd' => dflag++; vac->dflag++; 'v' => vflag++; * => warn(sprint("bad option: -%c", c)); arg->usage(); } args = arg->argv(); if(len args == 0) arg->usage(); (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"); topde: ref Direntry; if(len args == 1 && ((nil, d) := sys->stat(hd args)).t0 == 0 && d.mode&Sys->DMDIR) { topde = Direntry.mk(d); topde.elem = name; } else { topde = Direntry.new(); topde.elem = name; topde.uid = topde.gid = user(); topde.mode = 8r777|Vac->Modedir; topde.mtime = topde.atime = 0; } topde.ctime = daytime->now(); s := Sink.new(session, blocksize); ms := MSink.new(session, blocksize); for(; args != nil; args = tl args) writepath(hd args, s, ms); say("tree written"); e0 := s.finish(); if(e0 == nil) error(sprint("writing top entry: %r")); e1 := ms.finish(); if(e1 == nil) error(sprint("writing top meta entry: %r")); say(sprint("top entries written (%s, %s)", e0.score.text(), e1.score.text())); s2 := MSink.new(session, blocksize); if(s2.add(topde) < 0) error(sprint("adding direntry for top entries: %r")); e2 := s2.finish(); say("top meta entry written, "+e2.score.text()); td := array[Entrysize*3] of byte; td[0*Entrysize:] = e0.pack(); td[1*Entrysize:] = e1.pack(); td[2*Entrysize:] = e2.pack(); (tok, tscore) := session.write(Dirtype, td); if(tok < 0) error(sprint("writing top-level entries: %r")); say("top entry written, "+tscore.text()); root := Root.new(name, "vac", tscore, blocksize, nil); rd := root.pack(); if(rd == nil) error(sprint("root pack: %r")); (rok, rscore) := session.write(Roottype, rd); if(rok < 0) error(sprint("writing root score: %r")); say("root written, "+rscore.text()); print("vac:%s\n", rscore.text()); if(session.sync() < 0) error(sprint("syncing server: %r"));} writepath(path: string, s: ref Sink, ms: ref MSink){ if(vflag) print("%s\n", path);say("writepath "+path); fd := sys->open(path, sys->OREAD); if(fd == nil) error(sprint("opening %s: %r", path)); (ok, dir) := sys->fstat(fd); if(ok < 0) error(sprint("fstat %s: %r", path));say("writepath: file opened"); if(dir.mode&sys->DMAUTH) { warn(path+": is auth file, skipping"); return; } if(dir.mode&sys->DMTMP) { warn(path+": is temporary file, skipping"); return; } e, me: ref Entry; de: ref Direntry; if(dir.mode & sys->DMDIR) {say("writepath: file is dir"); ns := Sink.new(session, blocksize); nms := MSink.new(session, blocksize); for(;;) { (n, dirs) := sys->dirread(fd); if(n == 0) break; if(n < 0) error(sprint("dirread %s: %r", path)); for(i := 0; i < len dirs; i++) { d := dirs[i]; npath := path+"/"+d.name; writepath(npath, ns, nms); } } e = ns.finish(); if(e == nil) error(sprint("error flushing dirsink for %s: %r", path)); me = nms.finish(); if(me == nil) error(sprint("error flushing metasink for %s: %r", path)); } else {say("writepath: file is normale file"); e = writefile(path, fd); if(e == nil) error(sprint("error flushing filesink for %s: %r", path)); }say("writepath: wrote path, "+e.score.text()); de = Direntry.mk(dir);say("writepath: have direntry"); i := s.add(e); if(i < 0) error(sprint("adding entry to sink: %r")); mi := 0; if(me != nil) mi = s.add(me); if(mi < 0) error(sprint("adding mentry to sink: %r")); de.entry = i; de.mentry = mi; i = ms.add(de); if(i < 0) error(sprint("adding direntry to msink: %r"));say("writepath done");} writefile(path: string, fd: ref Sys->FD): ref Entry{ bio := bufio->fopen(fd, bufio->OREAD); if(bio == nil) error(sprint("bufio opening %s: %r", path)); say(sprint("bufio opened path %s", path)); f := File.new(session, Datatype, blocksize); for(;;) { buf := array[blocksize] of byte; n := 0; while(n < len buf) { want := len buf - n; have := bio.read(buf[n:], want); if(have == 0) break; if(have < 0) error(sprint("reading %s: %r", path)); n += have; } say(sprint("have buf, length %d", n)); if(f.write(buf[:n]) < 0) error(sprint("writing %s: %r", path)); if(n != len buf) break; } bio.close(); return f.finish();} user(): string{ if((fd := sys->open("/dev/user", Sys->OREAD)) != nil && (n := sys->read(fd, d := array[128] of byte, len d)) > 0) return string d[:n]; return "nobody";} error(s: string){ warn(s); raise "fail:"+s;} warn(s: string){ fprint(fildes(2), "%s\n", s);} say(s: string){ if(dflag) warn(s);}
implement Vacput;
include "sys.m";
sys: Sys;
include "draw.m";
include "daytime.m";
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "arg.m";
include "string.m";
include "venti.m";
include "vac.m";
daytime: Daytime;
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, File, Sink, MSink: import vac;
Vacput: module {
init: fn(nil: ref Draw->Context, args: list of string);
};
addr := "net!$venti!venti";
dflag := 0;
vflag := 0;
blocksize := vac->Dsize;
session: ref Session;
name := "vac";
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
daytime = load Daytime Daytime->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] [-b blocksize] [-n name] path ...", arg->progname()));
while((c := arg->opt()) != 0)
case c {
'a' => addr = arg->earg();
'b' => blocksize = int arg->earg();
'n' => name = arg->earg();
'd' => dflag++;
vac->dflag++;
'v' => vflag++;
* => warn(sprint("bad option: -%c", c));
arg->usage();
}
args = arg->argv();
if(len args == 0)
arg->usage();
(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");
topde: ref Direntry;
if(len args == 1 && ((nil, d) := sys->stat(hd args)).t0 == 0 && d.mode&Sys->DMDIR) {
topde = Direntry.mk(d);
topde.elem = name;
} else {
topde = Direntry.new();
topde.elem = name;
topde.uid = topde.gid = user();
topde.mode = 8r777|Vac->Modedir;
topde.mtime = topde.atime = 0;
}
topde.ctime = daytime->now();
s := Sink.new(session, blocksize);
ms := MSink.new(session, blocksize);
for(; args != nil; args = tl args)
writepath(hd args, s, ms);
say("tree written");
e0 := s.finish();
if(e0 == nil)
error(sprint("writing top entry: %r"));
e1 := ms.finish();
if(e1 == nil)
error(sprint("writing top meta entry: %r"));
say(sprint("top entries written (%s, %s)", e0.score.text(), e1.score.text()));
s2 := MSink.new(session, blocksize);
if(s2.add(topde) < 0)
error(sprint("adding direntry for top entries: %r"));
e2 := s2.finish();
say("top meta entry written, "+e2.score.text());
td := array[Entrysize*3] of byte;
td[0*Entrysize:] = e0.pack();
td[1*Entrysize:] = e1.pack();
td[2*Entrysize:] = e2.pack();
(tok, tscore) := session.write(Dirtype, td);
if(tok < 0)
error(sprint("writing top-level entries: %r"));
say("top entry written, "+tscore.text());
root := Root.new(name, "vac", tscore, blocksize, nil);
rd := root.pack();
if(rd == nil)
error(sprint("root pack: %r"));
(rok, rscore) := session.write(Roottype, rd);
if(rok < 0)
error(sprint("writing root score: %r"));
say("root written, "+rscore.text());
print("vac:%s\n", rscore.text());
if(session.sync() < 0)
error(sprint("syncing server: %r"));
}
writepath(path: string, s: ref Sink, ms: ref MSink)
{
if(vflag)
print("%s\n", path);
say("writepath "+path);
fd := sys->open(path, sys->OREAD);
if(fd == nil)
error(sprint("opening %s: %r", path));
(ok, dir) := sys->fstat(fd);
if(ok < 0)
error(sprint("fstat %s: %r", path));
say("writepath: file opened");
if(dir.mode&sys->DMAUTH) {
warn(path+": is auth file, skipping");
return;
}
if(dir.mode&sys->DMTMP) {
warn(path+": is temporary file, skipping");
return;
}
e, me: ref Entry;
de: ref Direntry;
if(dir.mode & sys->DMDIR) {
say("writepath: file is dir");
ns := Sink.new(session, blocksize);
nms := MSink.new(session, blocksize);
for(;;) {
(n, dirs) := sys->dirread(fd);
if(n == 0)
break;
if(n < 0)
error(sprint("dirread %s: %r", path));
for(i := 0; i < len dirs; i++) {
d := dirs[i];
npath := path+"/"+d.name;
writepath(npath, ns, nms);
}
}
e = ns.finish();
if(e == nil)
error(sprint("error flushing dirsink for %s: %r", path));
me = nms.finish();
if(me == nil)
error(sprint("error flushing metasink for %s: %r", path));
} else {
say("writepath: file is normale file");
e = writefile(path, fd);
if(e == nil)
error(sprint("error flushing filesink for %s: %r", path));
}
say("writepath: wrote path, "+e.score.text());
de = Direntry.mk(dir);
say("writepath: have direntry");
i := s.add(e);
if(i < 0)
error(sprint("adding entry to sink: %r"));
mi := 0;
if(me != nil)
mi = s.add(me);
if(mi < 0)
error(sprint("adding mentry to sink: %r"));
de.entry = i;
de.mentry = mi;
i = ms.add(de);
if(i < 0)
error(sprint("adding direntry to msink: %r"));
say("writepath done");
}
writefile(path: string, fd: ref Sys->FD): ref Entry
{
bio := bufio->fopen(fd, bufio->OREAD);
if(bio == nil)
error(sprint("bufio opening %s: %r", path));
say(sprint("bufio opened path %s", path));
f := File.new(session, Datatype, blocksize);
for(;;) {
buf := array[blocksize] of byte;
n := 0;
while(n < len buf) {
want := len buf - n;
have := bio.read(buf[n:], want);
if(have == 0)
break;
if(have < 0)
error(sprint("reading %s: %r", path));
n += have;
}
say(sprint("have buf, length %d", n));
if(f.write(buf[:n]) < 0)
error(sprint("writing %s: %r", path));
if(n != len buf)
break;
}
bio.close();
return f.finish();
}
user(): string
{
if((fd := sys->open("/dev/user", Sys->OREAD)) != nil
&& (n := sys->read(fd, d := array[128] of byte, len d)) > 0)
return string d[:n];
return "nobody";
}
error(s: string)
{
warn(s);
raise "fail:"+s;
}
warn(s: string)
{
fprint(fildes(2), "%s\n", s);
}
say(s: string)
{
if(dflag)
warn(s);
}