// Walk to the given rid checking out perms when t.ai is not nil. // Returns also the gid and mode even when no perms are checked. func (t *Lfs) canWalkTo(rid string, forwhat int) (string, uint64, error) { if !t.readattrs || rid == "/Ctl" { return dbg.Usr, 0777, nil } noperm := t.NoPermCheck || t.ai == nil elems := zx.Elems(rid) fpath := t.path pgid := "" var pmode uint64 if len(elems) == 0 { elems = append(elems, "/") } for len(elems) > 0 { if noperm { // skip to just the final step if len(elems) > 1 { fpath = zx.Path(t.path, path.Dir(rid)) elems = elems[len(elems)-1:] } } pd := zx.Dir{ "name": elems[0], } fpath = zx.Path(fpath, elems[0]) elems = elems[1:] st, err := os.Stat(fpath) if err != nil { return "", 0, err } mode := st.Mode() m := int64(mode & 0777) pd["mode"] = "0" + strconv.FormatInt(m, 8) t.fileAttrs(fpath, pd) if !noperm && len(elems) > 0 && !pd.CanWalk(t.ai) { return "", 0, dbg.ErrPerm } if len(elems) == 0 { pgid = pd["Gid"] pmode = uint64(pd.Int("mode")) } if !noperm && len(elems) == 0 && forwhat != 0 { if !pd.Can(t.ai, forwhat) { return "", 0, dbg.ErrPerm } } } if pgid == "" { pgid = dbg.Usr } if pmode == 0 { pmode = 0775 } return pgid, pmode, nil }
func (t *Fs) walk(rid string) (File, error) { rid, err := zx.AbsPath(rid) if err != nil { return nil, err } if rid == "/" { return t.root, nil } if rid == "/Ctl" { return nil, nil } els := zx.Elems(rid) f := t.root p := "/" var d zx.Dir for _, e := range els { t.Dprintf("walk %s %s...\n", f, e) d, err = f.Stat() if err != nil { t.Dprintf("\tstat: %s\n", f, err) return nil, err } if d["type"] != "d" { t.Dprintf("\tnot dir\n") return nil, fmt.Errorf("%s: %s", p, dbg.ErrNotDir) } if !t.NoPermCheck && !d.CanWalk(t.ai) { t.Dprintf("\tno perm\n") return nil, fmt.Errorf("%s: %s", p, dbg.ErrPerm) } wf, ok := f.(Walker) if !ok { t.Dprintf("\tnot walker\n") return nil, fmt.Errorf("%s: %s: %s", p, e, dbg.ErrNotExist) } f, err = wf.Walk(e) if err != nil { t.Dprintf("\twalk: %s\n", err) return nil, err } p = zx.Path(p, e) t.Dprintf("walked %s\n", f) } return f, nil }
// 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 }