// d is a dup and can be changed. func (f *mFile) find(d zx.Dir, p *pred.Pred, spref, dpref string, lvl int, c chan<- zx.Dir, ai *auth.Info) { match, pruned, err := p.EvalAt(d, lvl) f.dprintf("find at %d %s\n\t%v\n\t%v %v %v\n\n", lvl, d.Long(), p, match, pruned, err) if pruned { if !match { d["err"] = "pruned" } c <- d return } if d["type"] == "d" && err == nil { f.mlk.Lock() if !f.t.NoPermCheck && !f.d.CanWalk(ai) { err = dbg.ErrPerm } f.mlk.Unlock() } if err != nil { d["err"] = err.Error() c <-d return } if d["rm"] != "" { return } if match { if ok := c <- d; !ok { return } } if d["type"] != "d" { return } f.clk.Lock() child := make([]*mFile, len(f.child)) copy(child, f.child) f.clk.Unlock() if f.name == "/" { nc := []*mFile{ &mFile{name: "Ctl", d: ctldir.Dup(), t: f.t}, } nc[0].d["tpath"] = f.t.path child = append(nc, child...) } for _, cf := range child { cf.mlk.Lock() cd := cf.d.Dup() cf.mlk.Unlock() // fmt.Printf("child %s\n", cd) if cd["rm"] != "" { continue } if spref != dpref { cpath := cd["path"] suff := zx.Suffix(cpath, spref) cd["path"] = zx.Path(dpref, suff) } cf.find(cd, p, spref, dpref, lvl+1, c, ai) } } func (t *Fs) Find(rid, fpred, spref, dpref string, depth int) <-chan zx.Dir { t.dprintf("find %s '%s' '%s' '%s' %d\n", rid, fpred, spref, dpref, depth) cs := t.IOstats.NewCall(zx.Sfind) dc := make(chan zx.Dir) go func() { rid, err := zx.AbsPath(rid) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } f, _, err := t.walk(rid, nil) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } p, err := pred.New(fpred) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } cs.Sending() f.mlk.Lock() d := f.d.Dup() f.mlk.Unlock() if spref != dpref { suff := zx.Suffix(rid, spref) d["path"] = zx.Path(dpref, suff) } f.find(d, p, spref, dpref, depth, dc, t.ai) cs.End(err != nil) t.dprintf("find %s: ok\n", rid) close(dc) }() return dc } func (t *Fs) FindGet(rid, fpred, spref, dpref string, depth int) <-chan zx.DirData { t.dprintf("findget %s '%s' '%s' '%s' %d\n", rid, fpred, spref, dpref, depth) gc := make(chan zx.DirData) cs := t.IOstats.NewCall(zx.Sfindget) go func() { dc := t.Find(rid, fpred, spref, dpref, depth) // BUG: will stat a Sfind for d := range dc { g := zx.DirData{Dir: d} var datac chan []byte if d["err"]=="" && d["type"]=="-" { datac = make(chan []byte) g.Datac = datac } if ok := gc <- g; !ok { close(dc, cerror(gc)) break } if datac != nil { err := t.get(d["spath"], 0, zx.All, datac, nil) close(datac, err) } } err := cerror(dc) cs.End(err != nil) if err != nil { t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(gc, err) }() return gc } func (t *Fs) Dump(w io.Writer) { if t == nil { fmt.Fprintf(w, "<nil tree>\n") return } fmt.Fprintf(w, "tree [%s] path %s\n", t.name, t.path) t.root.Dump(w, 0) fmt.Fprintf(w, "\n") } func (f *mFile) Dump(w io.Writer, lvl int) { tabs := strings.Repeat(" ", lvl) if f == nil { fmt.Fprintf(w, "%s<nil file>\n", tabs) return } d := f.d.Dup() if d["path"] == "/" { d["size"] = "0" } fmt.Fprintf(w, "%s%s\n", tabs, d.TestFmt()) if d["type"] != "d" { fmt.Fprintf(w, "%s %d bytes\n", tabs, f.data.Len()) return } for _, c := range f.child { c.Dump(w, lvl+1) } }
func (t *Rfs) getrpc(rid string, msg *Msg) <-chan []byte { t.c.Debug = t.Dbg && VerbDebug c := make(chan []byte, 10) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sget, len(raw)) reqc <- raw close(reqc) some := false for rep := range repc { cs.Send(int64(len(rep))) if ok := c <- rep; !ok { close(repc, cerror(c)) break } some = true t.dprintf("get %s: ok\n", rid) } if !some { c <- nil } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("get %s: %s\n", rid, err) } else { t.dprintf("get %s: ok\n", rid) } close(c, err) }() return c } func (t *Rfs) Get(rid string, off, count int64, pred string) <-chan []byte { t.dprintf("get %s %d %d %q\n", rid, off, count, pred) msg := &Msg{Op: Tget, Rid: rid, Off: off, Count: count, Pred: pred} return t.getrpc(rid, msg) } func (t *Rfs) putrpc(rid string, msg *Msg, dc <-chan []byte) chan zx.Dir { t.c.Debug = t.Dbg && VerbDebug c := make(chan zx.Dir, 1) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sput, len(raw)) reqc <- raw nm := 0 tot := 0 for m := range dc { nm++ cs.Recv(int64(len(m))) if ok := reqc <- m; !ok { err := cerror(reqc) close(dc, err) close(c, err) cs.End(err != nil) return } if len(m) == 0 { break } tot += len(m) } close(reqc, cerror(dc)) rep := <-repc var err error var d zx.Dir if len(rep) == 0 { err = cerror(repc) } else { d, _, err = zx.UnpackDir(rep) if err==nil && d==nil { err = errors.New("null dir in put reply") } } cs.End(err != nil) if err == nil { t.dprintf("put %s: %s\n", rid, d) c <- d } else { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("put %s: %s\n", rid, err) } close(c, err) }() return c } func (t *Rfs) Put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) chan zx.Dir { t.dprintf("put %s %v %d '%s'\n", rid, d, off, pred) msg := &Msg{Op: Tput, Rid: rid, D: d, Off: off, Pred: pred} return t.putrpc(rid, msg, dc) } func (t *Rfs) errrpc(rid, op string, msg *Msg, k int) chan error { t.c.Debug = t.Dbg && VerbDebug c := make(chan error, 1) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() var cs *zx.CallStat if k >= 0 { cs = t.IOstats.NewCallSize(k, len(raw)) } reqc <- raw close(reqc) <-repc err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("%s %s: %s\n", op, rid, err) } else { t.dprintf("%s %s: ok\n", op, rid) } c <- err close(c, err) cs.End(err != nil) }() return c } func (t *Rfs) Fsys(name string) <-chan error { t.dprintf("fsys %s\n", name) msg := &Msg{Op: Tfsys, Rid: name} return t.errrpc(name, "fsys", msg, -1) } func (t *Rfs) Mkdir(rid string, d zx.Dir) chan error { msg := &Msg{Op: Tmkdir, Rid: rid, D: d} t.dprintf("mkdir %s %v\n", rid, d) return t.errrpc(rid, "mkdir", msg, zx.Smkdir) } func (t *Rfs) Move(from, to string) chan error { t.dprintf("move %s %s \n", from, to) msg := &Msg{Op: Tmove, Rid: from, To: to} return t.errrpc(from, "move", msg, zx.Smove) } func (t *Rfs) Remove(rid string) chan error { t.dprintf("remove %s\n", rid) msg := &Msg{Op: Tremove, Rid: rid} return t.errrpc(rid, "remove", msg, zx.Sremove) } func (t *Rfs) RemoveAll(rid string) chan error { t.dprintf("removeall %s\n", rid) msg := &Msg{Op: Tremoveall, Rid: rid} return t.errrpc(rid, "removeall", msg, zx.Sremoveall) } func (t *Rfs) Wstat(rid string, d zx.Dir) chan error { t.dprintf("wstat %s %v\n", rid, d) msg := &Msg{Op: Twstat, Rid: rid, D: d} return t.errrpc(rid, "wstat", msg, zx.Swstat) } func (t *Rfs) Find(rid, pred, spref, dpref string, depth int) <-chan zx.Dir { t.dprintf("find %s '%s' '%s' '%s' %d\n", rid, pred, spref, dpref, depth) dc := make(chan zx.Dir) msg := &Msg{Op: Tfind, Rid: rid, Pred: pred, Spref: spref, Dpref: dpref, Depth: depth} go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sfind, len(raw)) reqc <- raw close(reqc) some := false for rep := range repc { cs.Send(int64(len(rep))) d, _, _ := zx.UnpackDir(rep) if d != nil { d["addr"] = t.addr d["proto"] = "zx" } if ok := dc <- d; !ok { close(repc, cerror(dc)) break } some = true t.dprintf(rid, "find", "<- %v\n", d) } if !some { dc <- nil } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(dc, err) cs.End(err != nil) }() return dc } func (t *Rfs) FindGet(rid, pred, spref, dpref string, depth int) <-chan zx.DirData { t.dprintf("findget %s '%s' '%s' '%s' %d\n", rid, pred, spref, dpref, depth) dc := make(chan zx.DirData) msg := &Msg{Op: Tfindget, Rid: rid, Pred: pred, Spref: spref, Dpref: dpref, Depth: depth} go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sfind, len(raw)) reqc <- raw close(reqc) for rep := range repc { cs.Send(int64(len(rep))) d, _, _ := zx.UnpackDir(rep) if d != nil { d["addr"] = t.addr d["proto"] = "zx" } res := zx.DirData{Dir: d} var datc chan []byte if d["err"]=="" && d["type"]=="-" { datc = make(chan []byte) res.Datac = datc } if ok := dc <- res; !ok { close(repc, cerror(dc)) break } t.dprintf(rid, "find", "<- %v\n", d) if datc != nil { for rep := range repc { if len(rep) == 0 { break } if ok := datc <- rep; !ok { continue } } close(datc, cerror(repc)) } } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(dc, err) }() return dc }
// d is a dup and can be changed. func (t *Fs) find(f File, d zx.Dir, p *pred.Pred, spref, dpref string, lvl int, c chan<- zx.Dir, ai *auth.Info) { match, pruned, err := p.EvalAt(d, lvl) t.dprintf("find at %v\n\t%v\n\t%v %v %v\n\n", d, p, match, pruned, err) if pruned { if !match { d["err"] = "pruned" } c <- d return } if d["type"] == "d" && err == nil { if !t.NoPermCheck && !d.CanWalk(ai) { err = dbg.ErrPerm } } if err != nil { d["err"] = err.Error() c <-d return } if d["rm"] != "" { return } if match { if ok := c <- d; !ok { return } } if d["type"] != "d" || f == nil { return } wf, ok := f.(Walker) if !ok { return } ns, err := wf.Getdir() if err != nil { return } sort.Sort(sort.StringSlice(ns)) if d["name"] == "/" { cd := ctldir.Dup() if spref != dpref { cpath := cd["path"] suff := zx.Suffix(cpath, spref) cd["path"] = zx.Path(dpref, suff) } t.find(nil, cd, p, spref, dpref, lvl+1, c, ai) } for _, cnm := range ns { cf, err := wf.Walk(cnm) if err != nil { continue } cp := zx.Path(d["path"], cnm) cd, err := t.statf(cf, cp) if err != nil || cd["rm"] != "" { continue } cd = cd.Dup() if spref != dpref { cpath := cd["path"] suff := zx.Suffix(cpath, spref) cd["path"] = zx.Path(dpref, suff) } t.find(cf, cd, p, spref, dpref, lvl+1, c, ai) } } func (t *Fs) Find(rid, fpred, spref, dpref string, depth int) <-chan zx.Dir { t.dprintf("find %s '%s' '%s' '%s' %d\n", rid, fpred, spref, dpref, depth) cs := t.IOstats.NewCall(zx.Sfind) dc := make(chan zx.Dir) go func() { rid, err := zx.AbsPath(rid) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } f, err := t.walk(rid) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } p, err := pred.New(fpred) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } d, err := t.statf(f, rid) if err != nil { cs.End(err != nil) t.dprintf("find %s: %s\n", rid, err) close(dc, err) return } d = d.Dup() if spref != dpref { suff := zx.Suffix(rid, spref) d["path"] = zx.Path(dpref, suff) } t.find(f, d, p, spref, dpref, depth, dc, t.ai) cs.End(err != nil) t.dprintf("find %s: ok\n", rid) close(dc) }() return dc } // used only by findget func (t *Fs) get(rid string, datac chan<- []byte) error { f, err := t.walk(rid) if err != nil { return err } gf, ok := f.(Getter) if !ok { return nil } return gf.Get(0, -1, datac) } func (t *Fs) FindGet(rid, fpred, spref, dpref string, depth int) <-chan zx.DirData { t.dprintf("findget %s '%s' '%s' '%s' %d\n", rid, fpred, spref, dpref, depth) gc := make(chan zx.DirData) cs := t.IOstats.NewCall(zx.Sfindget) go func() { dc := t.Find(rid, fpred, spref, dpref, depth) // BUG: will stat a Sfind for d := range dc { g := zx.DirData{Dir: d} var datac chan []byte if d["err"] == "" && !t.NoPermCheck && d["type"] != "d" && !d.CanRead(t.ai) { d["err"] = dbg.ErrPerm.Error() } if d["err"]=="" && d["type"]!="d" { datac = make(chan []byte) g.Datac = datac } if ok := gc <- g; !ok { close(dc, cerror(gc)) break } if datac != nil { err := t.get(d["spath"], datac) close(datac, err) } } err := cerror(dc) cs.End(err != nil) if err != nil { t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(gc, err) }() return gc }