diff options
Diffstat (limited to 'appl/cmd')
| -rw-r--r-- | appl/cmd/mkfile | 6 | ||||
| -rw-r--r-- | appl/cmd/vacfs.b | 446 | ||||
| -rw-r--r-- | appl/cmd/vacget.b | 199 | ||||
| -rw-r--r-- | appl/cmd/vacput.b | 258 |
4 files changed, 909 insertions, 0 deletions
diff --git a/appl/cmd/mkfile b/appl/cmd/mkfile index 69cf60d0..29c1679f 100644 --- a/appl/cmd/mkfile +++ b/appl/cmd/mkfile @@ -160,6 +160,9 @@ TARG=\ unmount.dis\ uudecode.dis\ uuencode.dis\ + vacfs.dis\ + vacget.dis\ + vacput.dis\ wav2iaf.dis\ wc.dis\ webgrab.dis\ @@ -216,3 +219,6 @@ rawdbfs.dis: $MODDIR/styxservers.m import.dis: $MODDIR/encoding.m $MODDIR/factotum.m basename.dis: $MODDIR/names.m cleanname.dis: $MODDIR/names.m +vacfs.dis: $MODDIR/vac.m $MODDIR/venti.m +vacget.dis: $MODDIR/vac.m $MODDIR/venti.m +vacput.dis: $MODDIR/vac.m $MODDIR/venti.m diff --git a/appl/cmd/vacfs.b b/appl/cmd/vacfs.b new file mode 100644 index 00000000..5fffc98d --- /dev/null +++ b/appl/cmd/vacfs.b @@ -0,0 +1,446 @@ +implement Vacfs; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "arg.m"; +include "string.m"; +include "daytime.m"; +include "venti.m"; +include "vac.m"; +include "styx.m"; + styx: Styx; + Tmsg, Rmsg: import styx; +include "styxservers.m"; + +str: String; +daytime: Daytime; +venti: Venti; +vac: Vac; +styxservers: Styxservers; + +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; +Styxserver, Fid, Navigator, Navop, Enotfound: import styxservers; + +Vacfs: module { + init: fn(nil: ref Draw->Context, args: list of string); +}; + +addr := "net!$venti!venti"; +dflag := pflag := 0; +session: ref Session; + +ss: ref Styxserver; + +Elem: adt { + qid: int; + de: ref Direntry; + size: big; + pick { + File => vf: ref Vacfile; + Dir => vd: ref Vacdir; + pqid: int; + offset: int; + nprev: int; + prev: array of ref Sys->Dir; + } + + new: fn(nqid: int, vd: ref Vacdir, de: ref Direntry, pqid: int): ref Elem; + stat: fn(e: self ref Elem): ref Sys->Dir; +}; + +Qdir: adt { + qid: int; + cqids: list of (big, int); +}; + +elems := array[512] of list of ref Elem; +qids := array[512] of list of ref Qdir; +lastqid := 0; +qidscores: list of (string, int); + + +childget(qid: int, vqid: big): ref Elem +{ + for(l := qids[qid % len qids]; l != nil; l = tl l) { + if((hd l).qid != qid) + continue; + for(m := (hd l).cqids; m != nil; m = tl m) { + (vq, cq) := hd m; + if(vq == vqid) + return get(cq); + } + } + return nil; +} + +childput(qid: int, vqid: big): int +{ + qd: ref Qdir; + for(l := qids[qid % len qids]; l != nil; l = tl l) + if((hd l).qid == qid) { + qd = hd l; + break; + } + if(qd == nil) { + qd = ref Qdir(qid, nil); + qids[qid % len qids] = qd::nil; + } + qd.cqids = (vqid, ++lastqid)::qd.cqids; + return lastqid; +} + +scoreget(score: string): ref Elem +{ + for(l := qidscores; l != nil; l = tl l) { + (s, n) := hd l; + if(s == score) + return get(n); + } + return nil; +} + +scoreput(score: string): int +{ + qidscores = (score, ++lastqid)::qidscores; + return lastqid; +} + + +Elem.new(nqid: int, vd: ref Vacdir, de: ref Direntry, pqid: int): ref Elem +{ + (e, me) := vd.open(de); + if(e == nil) + return nil; + if(de.mode & Vac->Modedir) + return ref Elem.Dir(nqid, de, e.size, Vacdir.new(session, e, me), pqid, 0, 0, nil); + return ref Elem.File(nqid, de, e.size, Vacfile.new(session, e)); +} + +Elem.stat(e: self ref Elem): ref Sys->Dir +{ + d := e.de.mkdir(); + d.qid.path = big e.qid; + d.length = e.size; + return d; +} + +walk(ed: ref Elem.Dir, name: string): (ref Elem, string) +{ + if(name == "..") + return (get(ed.pqid), nil); + + if(ed.qid == 0) { + ne := scoreget(name); + if(ne == nil) { + (ok, score) := Score.parse(name); + if(ok != 0) + return (nil, "bad score: "+name); + + (vd, de, err) := vac->vdroot(session, score); + if(err != nil) + return (nil, err); + + nqid := scoreput(name); + ne = ref Elem.Dir(nqid, de, big 0, vd, ed.qid, 0, 0, nil); + set(ne); + } + return (ne, nil); + } + + de := ed.vd.walk(name); + if(de == nil) + return (nil, sprint("%r")); + ne := childget(ed.qid, de.qid); + if(ne == nil) { + nqid := childput(ed.qid, de.qid); + ne = Elem.new(nqid, ed.vd, de, ed.qid); + set(ne); + } + return (ne, nil); +} + +get(qid: int): ref Elem +{ + for(l := elems[qid % len elems]; l != nil; l = tl l) + if((hd l).qid == qid) + return hd l; + return nil; +} + +set(e: ref Elem) +{ + elems[e.qid % len elems] = e::elems[e.qid % len elems]; +} + +getfile(qid: int): ref Elem.File +{ + pick file := get(qid) { + File => return file; + } + error("internal error, getfile"); + return nil; +} + +getdir(qid: int): ref Elem.Dir +{ + pick d := get(qid) { + Dir => return d; + } + error("internal error, getdir"); + return nil; +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + arg := load Arg Arg->PATH; + str = load String String->PATH; + daytime = load Daytime Daytime->PATH; + venti = load Venti Venti->PATH; + styx = load Styx Styx->PATH; + styxservers = load Styxservers Styxservers->PATH; + vac = load Vac Vac->PATH; + if(venti == nil || vac == nil) + error("loading venti,vac"); + sys->pctl(sys->NEWPGRP, nil); + venti->init(); + vac->init(); + styx->init(); + styxservers->init(styx); + + arg->init(args); + arg->setusage(arg->progname()+" [-Ddp] [-a addr] [[tag:]score]"); + while((ch := arg->opt()) != 0) + case ch { + 'D' => styxservers->traceset(1); + 'a' => addr = arg->earg(); + 'd' => dflag++; + vac->dflag++; + 'p' => pflag++; + * => warn(sprint("bad option: -%c", ch)); + arg->usage(); + } + args = arg->argv(); + if(len args > 1) + arg->usage(); + + score: ref Score; + if(len args == 1) { + (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); + (ok, s) := Score.parse(scorestr); + if(ok != 0) + error("bad score: "+scorestr); + score = ref s; + } + + (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"); + + rqid := 0; + red: ref Elem; + if(args == nil) { + de := Direntry.new(); + de.uid = de.gid = de.mid = user(); + de.ctime = de.atime = de.mtime = daytime->now(); + de.mode = Vac->Modedir|8r755; + de.emode = Sys->DMDIR|8r755; + red = ref Elem.Dir(rqid, de, big 0, nil, rqid, 0, 0, nil); + } else { + (vd, de, err) := vac->vdroot(session, *score); + if(err != nil) + error(err); + rqid = ++lastqid; + red = ref Elem.Dir(rqid, de, big 0, vd, rqid, 0, 0, nil); + } + set(red); + say(sprint("have root, qid=%d", rqid)); + + navchan := chan of ref Navop; + nav := Navigator.new(navchan); + spawn navigator(navchan); + + msgc: chan of ref Tmsg; + (msgc, ss) = Styxserver.new(sys->fildes(0), nav, big rqid); + + for(;;) { + pick m := <- msgc { + Readerror => + say("read error: "+m.error); + + Read => + say(sprint("have read, offset=%ubd count=%d", m.offset, m.count)); + (c, err) := ss.canread(m); + if(c == nil){ + ss.reply(ref Rmsg.Error(m.tag, err)); + break; + } + if(c.qtype & Sys->QTDIR){ + ss.default(m); + break; + } + + ef := getfile(int c.path); + n := m.count; + a := array[n] of byte; + have := ef.vf.pread(a, n, m.offset); + if(have < 0) { + ss.reply(ref Rmsg.Error(m.tag, sprint("%r"))); + break; + } + ss.reply(ref Rmsg.Read(m.tag, a[:have])); + + Open => + (c, mode, f, err) := canopen(m); + if(c == nil){ + ss.reply(ref Rmsg.Error(m.tag, err)); + break; + } + c.open(mode, f.qid); + ss.reply(ref Rmsg.Open(m.tag, f.qid, ss.iounit())); + + + * => + ss.default(m); + } + } +} + +canopen(m: ref Tmsg.Open): (ref Fid, int, ref Sys->Dir, string) +{ + c := ss.getfid(m.fid); + if(c == nil) + return (nil, 0, nil, Styxservers->Ebadfid); + if(c.isopen) + return (nil, 0, nil, Styxservers->Eopen); + (f, err) := ss.t.stat(c.path); + if(f == nil) + return (nil, 0, nil, err); + mode := styxservers->openmode(m.mode); + if(mode == -1) + return (nil, 0, nil, Styxservers->Ebadarg); + if(mode != Sys->OREAD && f.qid.qtype & Sys->QTDIR) + return (nil, 0, nil, Styxservers->Eperm); + if(!pflag && !styxservers->openok(c.uname, m.mode, f.mode, f.uid, f.gid)) + return (nil, 0, nil, Styxservers->Eperm); + if(m.mode & Sys->ORCLOSE) + return (nil, 0, nil, Styxservers->Eperm); + return (c, mode, f, err); +} + +navigator(c: chan of ref Navop) +{ +loop: + for(;;) { + navop := <- c; + say(sprint("have navop, path=%bd", navop.path)); + pick n := navop { + Stat => + say(sprint("have stat")); + n.reply <-= (get(int n.path).stat(), nil); + + Walk => + say(sprint("have walk, name=%q", n.name)); + ed := getdir(int n.path); + (ne, err) := walk(ed, n.name); + if(err != nil) { + n.reply <-= (nil, err); + break; + } + n.reply <-= (ne.stat(), nil); + + Readdir => + say(sprint("have readdir path=%bd offset=%d count=%d", n.path, n.offset, n.count)); + if(n.path == big 0) { + n.reply <-= (nil, nil); + break; + } + ed := getdir(int n.path); + if(n.offset == 0) { + ed.vd.rewind(); + ed.offset = 0; + ed.prev = array[0] of ref Sys->Dir; + } + skip := n.offset-ed.offset; + if(skip > 0) { + ed.prev = ed.prev[skip:]; + ed.nprev -= skip; + ed.offset += skip; + } + if(len ed.prev < n.count) { + newprev := array[n.count] of ref Sys->Dir; + newprev[:] = ed.prev; + ed.prev = newprev; + } + while(ed.nprev < n.count) { + (ok, de) := ed.vd.readdir(); + if(ok < 0) { + say(sprint("readdir error: %r")); + n.reply <-= (nil, sprint("reading directory: %r")); + continue loop; + } + if(de == nil) + break; + ne := childget(ed.qid, de.qid); + if(ne == nil) { + nqid := childput(ed.qid, de.qid); + ne = Elem.new(nqid, ed.vd, de, ed.qid); + } + d := ne.stat(); + ed.prev[ed.nprev++] = d; + n.reply <-= (d, nil); + } + n.reply <-= (nil, nil); + } + } +} + +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) +{ + killgrp(); + 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); +} + +killgrp() +{ + fd := sys->open("/prog/"+string sys->pctl(0, nil)+"/ctl", sys->OWRITE); + if(fd != nil) + sys->fprint(fd, "killgrp\n"); +} 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); +} diff --git a/appl/cmd/vacput.b b/appl/cmd/vacput.b new file mode 100644 index 00000000..e01bdd36 --- /dev/null +++ b/appl/cmd/vacput.b @@ -0,0 +1,258 @@ +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); +} |
