コード例 #1
0
ファイル: fstest.go プロジェクト: Christopheraburns/clive
func chkdirs(t Fataler, fs zx.Tree, d zx.Dir, recur bool) {
	if d["path"] == "" {
		t.Fatalf("no path in <%s>", d)
	}
	if d["type"] != "d" {
		return
	}
	dents, err := zx.GetDir(fs, d["path"])
	if err != nil {
		t.Fatalf("getdir: %s: %s", d["path"], err)
	}
	if d["size"] != fmt.Sprintf("%d", len(dents)) {
		t.Logf("%s: size %s len(dents) %d", d["path"], d["size"], len(dents))
		t.Logf("d: %s\n", d.Long())
		for _, cd := range dents {
			t.Logf("\t%s\n", cd.Long())
		}
		t.Fatalf("bad dir size")
	}
	if recur {
		for _, cd := range dents {
			chkdirs(t, fs, cd, true)
		}
	}
}
コード例 #2
0
ファイル: file.go プロジェクト: chengguozhen/clive
// Dial the server for this dir (if not already dialed) and return it,
// the dir addr is updated.
func DirFs(d zx.Dir) (zx.Fs, error) {
	switch p := d.Proto(); p {
	case "lfs":
		addr := d["addr"]
		toks := strings.Split(d["addr"], "!") // lfs!root!/path
		if len(toks) != 3 {
			return nil, fmt.Errorf("ns: no zux tree for addr %q", addr)
		}
		fullpath := fpath.Join(toks[1], toks[2])
		fs, root, rel := Lfs(fullpath)
		if fs == nil {
			return nil, fmt.Errorf("ns: no zux tree for addr %q", addr)
		}
		d["addr"] = "lfs!" + root + "!" + rel
		return fs, nil
	case "zx":
		addr := d.SAddr()
		if len(addr) < 3 {
			panic("DirFs bug")
		}
		addr = addr[3:] // remove zx!
		// rzx does cache dials, no need to do it again here.
		return rzx.Dial(addr, auth.TLSclient)
	default:
		return nil, fmt.Errorf("ns: no tree for addr %q", d["addr"])
	}
}
コード例 #3
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) wstat(rid string, d zx.Dir) error {
	f, err := t.walk(rid)
	if err != nil {
		return err
	}
	ud := d.UsrAttrs()
	d, err = f.Stat()
	if err != nil {
		return err
	}
	ai := t.ai
	if t.NoPermCheck {
		ai = nil
	}
	if !t.WstatAll || t.ai != nil {
		if err := d.CanWstat(ai, ud); err != nil {
			return err
		}
	}
	if wsf, ok := f.(Wstater); !ok {
		if _, ok := f.(Putter); !ok {
			return fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
		}
		// ignore wstats if there's Put so that echo > file works.
		return nil
	} else {
		return wsf.Wstat(ud)
	}
}
コード例 #4
0
ファイル: ch.go プロジェクト: chengguozhen/clive
func ch(d, nd zx.Dir) error {
	if nd["mode"] != "" {
		nd = nd.Dup()
		chmod(d, nd["mode"])
	}
	_, err := cmd.Wstat(d["path"], nd)
	return err
}
コード例 #5
0
ファイル: mvf.go プロジェクト: chengguozhen/clive
func mv1(src, dst zx.Dir) error {
	cmd.VWarn("%s %s", src["Upath"], dst["Upath"])
	cmd.Dprintf("mv1: %s %s %s %s\n", src.SAddr(), src["Rpath"], dst.SAddr(), dst["Rpath"])
	if dry {
		return nil
	}
	return cmd.Move(src["path"], dst["path"])
}
コード例 #6
0
ファイル: pred.go プロジェクト: Christopheraburns/clive
/*
	Execute the part of the ns.Find operation that evaluates p
	at the tree rooted at d (considering that its level is the one
	indicated). Found entries are sent through the given channel,
	which is closed only upon errors.

	This is useful to implement ns.Find when writting services.
*/
func (p *Pred) FindAt(fs zx.Sender, d zx.Dir, c chan<- zx.Dir, lvl int) {
	match, pruned, err := p.EvalAt(d, lvl)
	if err != nil {
		close(c, err)
		return
	}
	if pruned {
		nd := d.Dup()
		nd["err"] = "pruned"
		c <- nd
		return
	}
	if d["rm"] != "" {
		return
	}
	var ds []zx.Dir
	if d["type"] == "d" {
		ds, err = zx.GetDir(fs, d["path"])
	}
	if err != nil {
		nd := d.Dup()
		nd["err"] = err.Error()
		c <- nd
		return
	}
	if match {
		if ok := c <- d; !ok {
			return
		}
	}
	for i := 0; i < len(ds); i++ {
		cd := ds[i]
		if cd["rm"] != "" {
			continue
		}
		p.FindAt(fs, cd, c, lvl+1)
	}
}

func Find(fs zx.Tree, path, pred string) <-chan zx.Dir {
	c := make(chan zx.Dir)
	go func() {
		d, err := zx.Stat(fs, path)
		if d == nil {
			close(c, err)
			return
		}
		x, err := New(pred)
		if err != nil {
			close(c, err)
			return
		}
		x.FindAt(fs, d, c, 0)
		close(c)
	}()
	return c
}
コード例 #7
0
ファイル: cmp.go プロジェクト: Christopheraburns/clive
// does not check attributes that indicate that data changed.
func metaChanged(d0, d1 zx.Dir) bool {
	ud0 := d0.UsrAttrs()
	ud1 := d1.UsrAttrs()
	for _, k := range ignoredAttrs {
		delete(ud0, k)
		delete(ud1, k)
	}
	return !zx.EqDir(ud0, ud1)
}
コード例 #8
0
ファイル: dir.go プロジェクト: Christopheraburns/clive
// Make a new Dir form a zd.Dir
func (z *Cfs) newDir(d zx.Dir) *Dir {
	zd := &Dir{
		z:     z,
		d:     d,
		path:  d["path"],
		mode:  uint(d.Uint64("mode")&0777),
		epoch: *z.epoch,
	}
	if zd.mode == 0 {
		zd.mode = 0777
	}
	return zd
}
コード例 #9
0
ファイル: fstest.go プロジェクト: Christopheraburns/clive
func Gets(t Fataler, fss ...zx.Tree) {
	for i := 0; i < Repeats; i++ {
		for _, fs := range fss {
			for _, p := range GetFPaths {
				printf("getall %s\n", p)
				dat, err := zx.GetAll(fs, p)
				if err != nil {
					t.Fatalf("get %s: %s", p, err)
				}
				printf("got %d bytes \n\n", len(dat))
				if string(dat) != string(FileData[p]) {
					printf("got <%s>\nexpected<%s>\n",
						string(dat), string(FileData[p]))
					t.Fatalf("%s: bad data", p)
				}
			}

			for _, p := range GetDPaths {
				printf("getall %s\n", p)
				dat, err := zx.GetAll(fs, p)
				if err != nil {
					t.Fatalf("get %s: %s", p, err)
				}
				var d zx.Dir
				ents := []string{}
				for len(dat) > 0 {
					d, dat, err = zx.UnpackDir(dat)
					if err != nil {
						t.Fatalf("dir: %s", err)
					}
					if d["path"] == "/Ctl" || d["path"] == "/Chg" {
						continue
					}
					ents = append(ents, d.TestFmt())
				}
				if strings.Join(GetDOuts[p], "\n") != strings.Join(ents, "\n") {
					t.Fatalf("bad dir data for %s", p)
				}
				printf("got %d ents (ctl, chg excluded)\n", len(ents))
			}
			for _, p := range BadPaths {
				dat, err := zx.GetAll(fs, p)
				if err==nil || len(dat)>0 {
					t.Fatalf("get %s didn't fail", p)
				}
			}
			printf("\n")
		}
	}
}
コード例 #10
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) error {
	pf, err := t.walk(path.Dir(rid))
	if err != nil {
		return err
	}
	pd, err := pf.Stat()
	if pd["type"] != "d" {
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrNotDir)
	}
	wpf, ok := pf.(Walker)
	if !ok {
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrPerm)
	}
	f, err := wpf.Walk(path.Base(rid))
	if err != nil && !dbg.IsNotExist(err) {
		return err
	}
	if err != nil {
		if err := t.matchDir(rid, nil, pred); err != nil {
			return err
		}
		if !t.NoPermCheck && !pd.CanWrite(t.ai) {
			return fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
		}
		if putf, ok := pf.(Putter); ok {
			return putf.Put(path.Base(rid), d, off, dc)
		}
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrPerm)
	} else {
		d, err := f.Stat()
		if err != nil {
			return err
		}
		if d["type"] == "d" {
			return fmt.Errorf("%s: %s", rid, dbg.ErrIsDir)
		}
		if err := t.matchDir(rid, d, pred); err != nil {
			return err
		}
		if !t.NoPermCheck && !d.CanWrite(t.ai) {
			return fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
		}
		if putf, ok := f.(Putter); ok {
			return putf.Put("", d, off, dc)
		}
		return fmt.Errorf("%s: %s", d["path"], dbg.ErrPerm)
	}
}
コード例 #11
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
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
}
コード例 #12
0
ファイル: rmf.go プロジェクト: fjballest/clive
func rmf(d zx.Dir) error {
	p := d.SPath()
	up := d["Upath"]
	if up == "" {
		up = d["path"]
	}
	if p == "" || p == "/" {
		cmd.Fatal("won't remove / in server for '%s'", up)
	}
	cmd.VWarn("rmf%s %s", astr[aflag], up)
	if dry {
		return nil
	}
	if aflag {
		return cmd.RemoveAll(d["path"])
	}
	return cmd.Remove(d["path"])
}
コード例 #13
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) Put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) chan zx.Dir {
	d = d.Dup()
	t.dprintf("put %s %v %d '%s'\n", rid, d, off, pred)
	cs := t.IOstats.NewCall(zx.Sput)
	c := make(chan zx.Dir, 1)
	go func() {
		cs.Sending()
		rid, err := zx.AbsPath(rid)
		var nm, n int64
		var nd zx.Dir
		if err == nil && rid == "/Ctl" {
			nc, xerr := t.putCtl(dc)
			if xerr == nil {
				nd = zx.Dir{"size": "0"}
				if DoSum {
					nd["Sum"] = zx.Zsum()
				}
				nd.SetTime("mtime", time.Now())
				nm = 1
				n = int64(nc)
			}
			err = xerr
		} else if err == nil {
			nd, nm, n, err = t.put(rid, d, off, dc, pred)
			cs.Sends(nm, n)
		}
		if err == nil {
			rd := zx.Dir{"size": nd["size"], "mtime": nd["mtime"]}
			if nd["Sum"] != "" {
				rd["Sum"] = nd["Sum"]
			}
			t.dprintf("put %s: %s (wrote %d)\n", rid, rd, n)
			c <- rd
		} else {
			t.dprintf("put %s: %s\n", rid, err)
			close(dc, err)
		}
		close(c, err)
		cs.End(err != nil)
	}()
	return c
}
コード例 #14
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) Get(rid string, off, count int64, pred string) <-chan []byte {
	t.dprintf("get %s %d %d %q\n", rid, off, count, pred)
	cs := t.IOstats.NewCall(zx.Sget)
	c := make(chan []byte)
	go func() {
		var d zx.Dir
		f, err := t.walk(rid)
		if f == nil && err == nil {	// Ctl
			d = ctldir.Dup()
		} else if err == nil {
			d, err = t.statf(f, rid)
		}
		if err == nil && !t.NoPermCheck {
			if !d.CanRead(t.ai) {
				err = fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
			}
		}
		if err == nil && pred != "" {
			err = t.match(d, err, rid, pred)
		}
		if err == nil {
			if d["path"] == "/Ctl" {
				err = t.getCtl(off, count, c)
			} else if d["type"] != "d" {
				if gf, ok := f.(Getter); ok {
					err = gf.Get(off, count, c)
				}
			} else {
				err = t.getdir(f, d, off, count, c)
			}
		}
		cs.End(err != nil)
		if err != nil {
			t.dprintf("get %s: %s\n", rid, err)
		} else {
			t.dprintf("get %s: ok\n", rid)
		}
		close(c, err)
	}()
	return c
}
コード例 #15
0
ファイル: cmp.go プロジェクト: Christopheraburns/clive
// Print d in DB format
func DbFmt(d zx.Dir) string {
	var b bytes.Buffer

	fmt.Fprintf(&b, "%-14s", d["path"])
	typ := d["type"]
	if typ == "" {
		fmt.Fprintf(&b, " -")
	} else {
		fmt.Fprintf(&b, " %s", typ)
	}
	if d["rm"] != "" {
		fmt.Fprintf(&b, " GONE")
	} else {
		fmt.Fprintf(&b, " 0%o", d.Mode())
	}
	uid := nouid(d["Uid"])
	gid := nouid(d["Gid"])
	wuid := nouid(d["Wuid"])
	fmt.Fprintf(&b, " %-8s %-8s %-8s", uid, gid, wuid)
	fmt.Fprintf(&b, " %8d", d.Int64("size"))
	if d["type"] != "d" {
		fmt.Fprintf(&b, " %d", d.Uint64("mtime"))
	}
	if d["err"] != "" {
		fmt.Fprintf(&b, " %s", d["err"])
	}
	return b.String()
}
コード例 #16
0
ファイル: xattrs.go プロジェクト: Christopheraburns/clive
// 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
}
コード例 #17
0
ファイル: arch.go プロジェクト: Christopheraburns/clive
func saveAttrs(dpath string, d zx.Dir) {
	nd := zx.Dir{"name": d["name"]}
	for k, v := range d {
		if zx.IsUpper(k) {
			nd[k] = v
		}
	}
	if len(nd) == 1 {
		return
	}
	dprintf("wrattr %s/%s %v\n", dpath, d["name"], nd)
	fn := path.Join(dpath, afname)
	fd, err := os.OpenFile(fn, os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		fd, err = os.OpenFile(fn, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	}
	if err != nil {
		return
	}
	defer fd.Close()
	fd.Write(nd.Pack())
}
コード例 #18
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) Put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) chan zx.Dir {
	d = d.UsrAttrs()
	t.dprintf("put %s %v %d '%s'\n", rid, d, off, pred)
	cs := t.IOstats.NewCall(zx.Sput)
	c := make(chan zx.Dir, 1)
	go func() {
		cs.Sending()
		rid, err := zx.AbsPath(rid)
		var nd zx.Dir
		if err == nil && rid == "/" {
			err = fmt.Errorf("/: %s", dbg.ErrPerm)
		}
		if err == nil && rid == "/Ctl" {
			xerr := t.putCtl(dc)
			if xerr == nil {
				nd = zx.Dir{"size": "0", "Sum": zx.Zsum()}
				nd.SetTime("mtime", time.Now())
			}
			err = xerr
		} else if err == nil {
			err = t.put(rid, d, off, dc, pred)
			if err == nil {
				nd, err = t.stat(rid)
			}
		}
		if err == nil {
			rd := zx.Dir{"size": nd["size"], "mtime": nd["mtime"], "Sum": nd["Sum"]}
			t.dprintf("put %s: %s\n", rid, rd)
			c <- rd
		} else {
			t.dprintf("put %s: %s\n", rid, err)
			close(dc, err)
		}
		close(c, err)
		cs.End(err != nil)
	}()
	return c
}
コード例 #19
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) wstat(rid string, d zx.Dir) error {
	f, _, err := t.walk(rid, nil)
	if err != nil {
		return err
	}
	f.mlk.Lock()
	defer f.mlk.Unlock()
	ai := t.ai
	if t.NoPermCheck {
		ai = nil
	}
	ud := d.UsrAttrs()
	if !t.WstatAll || t.ai != nil  {
		if err := f.d.CanWstat(ai, d); err != nil {
			return err
		}
	} else {
		if d["Wuid"] != "" {
			ud["Wuid"] = d["Wuid"]
		}
	}
	return f.wstat(ud)
}
コード例 #20
0
ファイル: nspace.go プロジェクト: Christopheraburns/clive
// See the Binder.Mount operation.
func (ns *Tree) Mount(fname string, d zx.Dir, flag Flag) <-chan error {
	c := make(chan error, 1)
	go func() {
		name, err := zx.AbsPath(fname)
		if err==nil && d==nil {
			err = errors.New("no mounted dir")
		}
		if err != nil {
			c <- err
			close(c, err)
			return
		}
		d = d.Dup()
		delete(d, "mtime")
		delete(d, "size")
		d["path"] = name
		d["name"] = path.Base(name)
		ns.lk.Lock()
		defer ns.lk.Unlock()
		c <- ns.mount(d, flag)
		close(c, err)
	}()
	return c
}
コード例 #21
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) mkdir(rid string, d zx.Dir) error {
	d = d.UsrAttrs()
	pf, err := t.walk(path.Dir(rid))
	if err != nil {
		return err
	}
	pd, err := pf.Stat()
	if pd["type"] != "d" {
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrNotDir)
	}
	wpf, ok := pf.(Mkdirer)
	if !ok {
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrPerm)
	}
	_, err = wpf.Walk(path.Base(rid))
	if err == nil {
		return fmt.Errorf("%s: %s", pd["path"], dbg.ErrExists)
	}
	if !t.NoPermCheck && !pd.CanWrite(t.ai) {
		return fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
	}
	return wpf.Mkdir(path.Base(rid), d)
	return fmt.Errorf("%s: %s", rid, dbg.ErrPerm)
}
コード例 #22
0
ファイル: fstest.go プロジェクト: Christopheraburns/clive
// set a fake mtime that can be predicted.
func TouchZX(fs zx.RWTree, path string) error {
	d := zx.Dir{}
	d.SetTime("mtime", time.Unix(xt/1e9, xt%1e9))
	xt += 1e9
	return <-fs.Wstat(path, d)
}
コード例 #23
0
ファイル: cmp.go プロジェクト: Christopheraburns/clive
func dataChanged(d0, d1 zx.Dir) bool {
	return d0["type"] != d1["type"] ||
		d0.Int64("size") != d1.Int64("size") ||
	  	d0.Int64("mtime") != d1.Int64("mtime") ||
		d0["Sum"] != "" && d1["Sum"] != "" && d0["Sum"] != d1["Sum"]
}
コード例 #24
0
ファイル: vfs.go プロジェクト: Christopheraburns/clive
// 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
}
コード例 #25
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) Mkdir(rid string, d zx.Dir) chan error {
	t.dprintf("mkdir %s %v\n", rid, d)
	cs := t.IOstats.NewCall(zx.Smkdir)
	c := make(chan error, 1)
	rid, err := zx.AbsPath(rid)
	if rid == "/" || rid=="/Ctl" {
		err = dbg.ErrExists
	}
	var f *mFile
	var left []string
	if err == nil {
		f, left, err = t.walk(rid, nil)
	}
	if err == nil {
		err = fmt.Errorf("'%s': %s", rid, dbg.ErrExists)
	} else if len(left) == 1 {
		err = nil
	}
	if err != nil {
		cs.End(true)
		t.dprintf("mkdir %s: %s\n", rid, err)
		c <- err
		close(c, err)
		return c
	}
	ud := d.UsrAttrs()
	delete(ud, "size")
	noinherit := false
	if m := ud["Mode"]; m != "" {
		ud["mode"] = m
		delete(ud, "Mode")
		noinherit = true
	}
	if ud["mode"] == "" {
		ud["mode"] = "0775"
	}
	if (!t.WstatAll || t.ai != nil) && !noinherit {
		f.mlk.Lock()
		ud["type"] = "d"
		ud.Inherit(f.d.Mode())
		delete(ud, "type")
		f.mlk.Unlock()
	}
	u := dbg.Usr
	if t.ai != nil {
		u = t.ai.Uid
	}
	nf := &mFile {
		name: left[0],
		d: zx.Dir{
			"mode": ud["mode"],
			"name": left[0],
			"path": rid,
			"spath": rid,
			"tpath": f.t.path,
			"Uid": u,
			"Gid": f.d["Gid"],
			"Wuid": u,
			"type": "d",
			"size": "0",
			"proto": "proc",
		},
		child: []*mFile{},
		t: t,
	}
	if DoSum {
		nf.d["Sum"] = zx.Zsum()
	}
	f.mlk.Lock()
	if !t.noPerms() && !f.d.CanWrite(t.ai) {
		err = fmt.Errorf("%s: %s", f, dbg.ErrPerm)
	}
	ai := t.ai
	if t.NoPermCheck {
		ai = nil
	}
	if err == nil && (!t.WstatAll || t.ai != nil)  {
		err = nf.d.CanWstat(ai, ud)
	}
	if err != nil {
		f.mlk.Unlock()
		cs.End(true)
		t.dprintf("mkdir %s: %s\n", rid, err)
		c <- err
		close(c, err)
		return c
	}
	f.mlk.Unlock()
	f.mlk.Lock()
	f.clk.Lock()
	f.attach(nf)
	f.clk.Unlock()
	f.mlk.Unlock()
	f = nf
	f.mlk.Lock()
	if t.WstatAll && t.ai == nil && d["Wuid"] != "" {
		ud["Wuid"] = d["Wuid"]
	}
	err = f.wstat(ud)
	f.mlk.Unlock()
	cs.End(err != nil)
	if err != nil {
		t.dprintf("mkdir %s: %s\n", rid, err)
	}
	c <- err
	close(c, err)
	return c
}
コード例 #26
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
// 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)
	}
	
}
コード例 #27
0
ファイル: zux_test.go プロジェクト: chengguozhen/clive
func TestAttrCache(t *testing.T) {
	os.Remove("/tmp/.zx")
	d := zx.Dir{"foo": "bar"}
	ac.set("/tmp/one", d)
	d = zx.Dir{"foo1": "bar1"}
	ac.set("/tmp/one", d)
	d = zx.Dir{"foo2": "bar2"}
	ac.set("/tmp/two", d)
	d = zx.Dir{}
	ac.get("/tmp/one", d)
	t.Logf("did get %s\n", d.LongFmt())
	if d.LongFmt() != `one foo:"bar" foo1:"bar1"` {
		t.Fatalf("didn't get attrs")
	}
	d = zx.Dir{}
	ac.get("/tmp/two", d)
	t.Logf("did get %s\n", d.LongFmt())
	if d.LongFmt() != `two foo2:"bar2"` {
		t.Fatalf("didn't get attrs")
	}
	ac.sync()
	d = zx.Dir{}
	ac.get("/tmp/one", d)
	t.Logf("did get %s\n", d.LongFmt())
	if d.LongFmt() != `one foo:"bar" foo1:"bar1"` {
		t.Fatalf("didn't get attrs after sync")
	}
	d = zx.Dir{"foo": "bar"}
	ac.set("/tmp/two", d)
	d = zx.Dir{}
	ac.get("/tmp/two", d)
	t.Logf("did get %s\n", d.LongFmt())
	if d.LongFmt() != `two foo:"bar" foo2:"bar2"` {
		t.Fatalf("didn't get attrs after sync")
	}
}
コード例 #28
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
func (t *Fs) put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) (zx.Dir, int64, int64, error) {
	noinherit := false
	if m := d["Mode"]; m != "" {
		d["mode"] = m
		delete(d, "Mode")
		noinherit = true
	}
	var pf *mFile
	f, left, err := t.walk(rid, &pf)
	if err != nil && !dbg.IsNotExist(err) || len(left) > 1|| d["mode"] == "" && err != nil {
		return nil, 0, 0, err
	}
	pmode := uint64(0755)
	if pf != nil {
		pf.mlk.Lock()
		pmode = pf.d.Mode()
		pf.mlk.Unlock()
	}
	app := false
	f.mlk.Lock()
	if err == nil && f.d["type"] == "d" || d["type"] == "d" {
		err = fmt.Errorf("%s: %s", f, dbg.ErrIsDir)
		f.mlk.Unlock()
		return nil, 0, 0, err
	}
	if !t.noPerms() && !f.d.CanWrite(t.ai) {
		err = fmt.Errorf("%s: %s", f, dbg.ErrPerm)
		f.mlk.Unlock()
		return nil, 0, 0, err
	}
	u := dbg.Usr
	if t.ai != nil {
		u = t.ai.Uid
	}
	if d == nil {
		d = zx.Dir{}
	}
	ai := t.ai
	if t.NoPermCheck {
		ai = nil
	}
	if d["mode"] == "" || err == nil {	// truncate or rewrite
		if err := t.matchDir(rid, f.d, pred); err != nil {
			f.mlk.Unlock()
			return nil, 0, 0, err
		}
		if !t.WstatAll || t.ai != nil {
			if err := f.d.CanWstat(ai, d); err != nil {
				f.mlk.Unlock()
				return nil, 0, 0, err
			}
		}
	} else {
		if err := t.matchDir(rid, nil, pred); err != nil {
			f.mlk.Unlock()
			return nil, 0, 0, err
		}
	}
	if d["mode"] == "" {
		if off < 0 {
			off = 0
			app = true
		}
		if t.WstatAll && t.ai == nil && d["Wuid"] != "" {
			f.d["Wuid"] = d["Wuid"]
		} else {
			f.d["Wuid"] = u
		}
		if d["size"] != "" {
			f.data.Truncate(d.Int64("size"))
			f.d["size"] = strconv.FormatInt(int64(f.data.Len()), 10)
		}
	} else if err == nil {
		// truncate existing file
		if !noinherit && (!t.WstatAll || t.ai != nil) {
			d.Inherit(pmode)
		}
		f.data.Truncate(d.Int64("size"))
		f.d["size"] = strconv.FormatInt(int64(f.data.Len()), 10)
		if t.WstatAll && t.ai == nil && d["Wuid"] != "" {
			f.d["Wuid"] = d["Wuid"]
		} else {
			f.d["Wuid"] = u
		}
	} else {
		// create a new file
		nf := &mFile {
			name: left[0],
			d: zx.Dir{
				"mode": d["mode"],
				"name": left[0],
				"path": rid,
				"spath": rid,
				"tpath": f.d["tpath"],
				"Uid": u,
				"Gid": f.d["Gid"],
				"Wuid": u,
				"type": "-",
				"size": "0",
				"proto": "proc",
			},
			data: &bufs.Blocks{Mutex: &sync.Mutex{}},
			t: t,
		}
		if !t.WstatAll || t.ai != nil  {
			if !noinherit {
				nf.d.Inherit(pmode)
				d["mode"] = nf.d["mode"]
			}
			if err := f.d.CanWstat(ai, d); err != nil {
				f.mlk.Unlock()
				return nil, 0, 0, err
			}
		} else if d["Wuid"] != "" {
			f.d["Wuid"] = d["Wuid"]
		}
		nf.data.Truncate(d.Int64("size"))
		nf.d["size"] = strconv.FormatInt(int64(nf.data.Len()), 10)
		f.clk.Lock()
		f.attach(nf)
		f.clk.Unlock()
		f.mlk.Unlock()
		f = nf
		f.mlk.Lock()
	}
	if app {
		off = int64(f.data.Len())
	}
	delete(d, "size")
	f.wstat(d.UsrAttrs())
	f.mlk.Unlock()

	n, err := f.data.RecvAtFrom(off, dc)

	f.mlk.Lock()
	defer f.mlk.Unlock()
	if DoSum {
		sum := f.data.Sum()
		f.d["Sum"] = sum
	}
	size := f.data.Len()
	f.d["size"] = strconv.Itoa(size)
	if d["mtime"] == "" {
		f.d.SetTime("mtime", time.Now())
	}
	return f.d.Dup(), 1, int64(n), err
}
コード例 #29
0
ファイル: cacheops.go プロジェクト: Christopheraburns/clive
// Compare d with the previous info in zd, and refresh its
// metadata, perhaps invalidating the data. Returns true
// if there is any change in data or metadata.
// this does not can changed(), the caller should do that.
func (zd *Dir) stated(from string, d zx.Dir, err error) (mchanged, dchanged bool, rerr error) {
	pzd := zd.parent
	if zd.path=="/Ctl" || zd.path=="/Chg" {
		return false, false, nil
	}
	if d==nil || d["rm"]!="" {
		if zd.ghost {
			zd.d["rm"] = "y" // safety first, but it's ok
			return false, false, dbg.ErrNotExist
		}
		zd.kill(from)
		if pzd!=nil && zd.epoch==0 {
			pzd.invalData() // cause a re-read.
		}
		return true, true, err
	}
	dchanged = zd.ghost
	zd.ghost = false
	mchanged = dchanged
	if mchanged {
		zd.cprintf(zd.path, "mchanged by data (%s)\n", from)
	} else {
		for k, v := range zd.d {
			nv := d[k]
			if nv != v {
				nv := d[k]
				if len(nv) > 6 {
					nv = nv[:6] + "..."
				}
				zd.cprintf(zd.path, "mchanged %s = %s (%s)\n", k, nv, from)
				mchanged = true
				break
			}
		}
	}
	if !mchanged {
		zd.cprintf("stated", "no changes (%s)\n", from)
		return dchanged, dchanged, nil
	}

	ot, nt := zd.d["type"], d["type"]
	overs, nvers := zd.d.Int("vers"), d.Int("vers")
	if nt==ot && nt!="d" && nvers!=0 && nvers<overs {
		zd.cprintf("stated", "old update ignored v %d (%s)\n", nvers, from)
		return dchanged, dchanged, nil
	}
	switch {
	case ot!=nt && (nt=="d" || ot=="d"):
		// file became dir or dir became file
		zd.child = nil
		dchanged = true
		zd.cprintf(zd.path, "dchanged type %s (%s)\n", nt, from)
	case zd.d["mtime"] != d["mtime"]:
		zd.cprintf(zd.path, "dchanged mtime %s (%s)\n", d["mtime"], from)
		dchanged = true
	case d["Sum"]!="" && zd.d["Sum"]!=d["Sum"]:
		ns := d["Sum"]
		if len(ns) > 6 {
			ns = ns[:6] + "..."
		}
		zd.cprintf(zd.path, "dchanged Sum %s (%s)\n", ns, from)
		dchanged = true
	case nt!="d" && zd.d["size"]!=d["size"]:
		zd.cprintf(zd.path, "dchanged size %s (%s)\n", d["size"], from)
		dchanged = true
	}
	if d["Sum"] == "" {
		d["Sum"] = zd.d["Sum"]
	}
	if d["vers"] == "" {
		d["vers"] = zd.d["vers"]
	}
	zd.d = d
	zd.mode = uint(zd.d.Uint64("mode")&0777)
	zd.refreshMeta()
	if dchanged {
		zd.invalData()
	}
	return mchanged, dchanged, nil
}
コード例 #30
0
ファイル: mfs.go プロジェクト: Christopheraburns/clive
// NB: Attributes that the user can't set are always ignored.
// If the user has no permissioin to set an attribute, that's an error.
// Setting an attribute to an empty string removes it.
// Uid, Gid, and Wuid can't be removed.
// Meta locking done by caller, might lock data on truncations
func (f *mFile) wstat(d zx.Dir) error {
	if len(d) == 0 {
		return nil
	}
	d = d.Dup()
	sum := ""
	if f.d["type"] != "d" {
		if _, ok := d["size"]; ok {
			sz := d.Int64("size")
			if sz < 0 {
				sz = 0
			}
			f.data.Truncate(sz)
			d["size"] = strconv.FormatInt(sz, 10)
			if DoSum {
				sum = f.data.Sum()
			}
		}
	} else {
		delete(d, "size")
	}
	if _, ok := d["mode"]; ok {
		mode := d.Int("mode")&0777
		d["mode"] = "0" + strconv.FormatInt(int64(mode), 8)
	}
	if _, ok := d["mtime"]; ok {
		d.SetTime("mtime", d.Time("mtime"))
	}
	if sum != "" {
		f.d["Sum"] = sum
	}
	ud := d.UsrAttrs()
	if d["Wuid"] != "" {
		ud["Wuid"] = d["Wuid"]
	}
	for k, v := range ud {
		if v == "" {
			delete(f.d, k)
		} else {
			f.d[k] = v
		}
	}
	return nil
}