Пример #1
0
func testfn(t *testing.T, fns ...func(t fstest.Fataler, fss ...zx.Tree)) {
	bufs.Size = 1 * 1024
	os.RemoveAll(tlfsdir)
	defer os.RemoveAll(tlfsdir)
	if err := os.Mkdir(tlfsdir, 0755); err != nil {
		t.Fatalf("lfs: %s", err)
	}
	os.Args[0] = "mdfs_test"
	dfs, err := lfs.New("	cache", tlfsdir, lfs.RW)
	if err != nil {
		t.Fatalf("lfs: %s", err)
	}
	dfs.SaveAttrs(true)
	mfs, err := New("example mfs", dfs)
	if err != nil {
		t.Fatalf("lfs: %s", err)
	}
	xfs, _ := mfs.AuthFor(&auth.Info{Uid: dbg.Usr, SpeaksFor: dbg.Usr, Ok: true})
	fs := xfs.(zx.RWTree)
	fstest.MkZXTree(t, fs)
	mfs.Dbg = testing.Verbose()
	dfs.Dbg = testing.Verbose()
	var fn func(t fstest.Fataler, fss ...zx.Tree)
	if len(fns) > 0 {
		fn = fns[0]
	}
	if fn != nil {
		if mfs.Dbg {
			defer func() {
				mfs.Dump(os.Stdout)
				dfs.Dump(os.Stdout)
			}()
		}
		for _, fn := range fns {
			fn(t, fs)
		}
	} else {
		d1, _ := zx.Stat(mfs, "/")
		printf("mfs st:\t%s\n", d1)
		d1, _ = zx.Stat(dfs, "/")
		printf("lfs st:\t%s\n", d1)
		// recreate, to test a reload
		mfs, err = New("example mfs", dfs)
		if err != nil {
			t.Fatalf("lfs: %s", err)
		}
		mfs.Dbg = testing.Verbose()
		xfs, _ = mfs.AuthFor(&auth.Info{Uid: dbg.Usr, SpeaksFor: dbg.Usr, Ok: true})
		fs = xfs.(zx.RWTree)
		if mfs.Dbg {
			defer func() {
				mfs.Dump(os.Stdout)
				dfs.Dump(os.Stdout)
			}()
		}
	}
	mfs.Dbg = false
	dfs.Dbg = false
	fstest.SameDump(t, mfs, dfs)
}
Пример #2
0
func Moves(t Fataler, fss ...zx.Tree) {
	fs := fss[0].(zx.RWTree)
	for _, mv := range MoveTests {
		printf("mv %s %s\n", mv.From, mv.To)
		err := <-fs.Move(mv.From, mv.To)
		if mv.Fails {
			if err==nil {
				t.Fatalf("mv %s didn't fail", mv.From)
			}
			continue
		}
		if err != nil {
			t.Fatalf("mv %s: %s", mv.From, err)
		}
		d, err := zx.Stat(fs, mv.To)
		if err != nil {
			t.Fatalf("stat %s: %s", mv.From, err)
		}
		delete(d, "Sum")
		r := d.LongTestFmt()
		printf("new stat: %s\n", r)
		if strings.Contains(mv.Res, "size X") {	// as is, with ctl, with ctl and chg
			r = strings.Replace(r, "size 5", "size X", 1)
			r = strings.Replace(r, "size 6", "size X", 1)
			r = strings.Replace(r, "size 7", "size X", 1)
		}
		r = strings.Replace(r, dbg.Usr, "nemo", -1)
		if mv.Res != "" && !strings.HasPrefix(r, mv.Res) {
			t.Fatalf("bad new stat %s", r)
		}
		if mv.Child != "" {
			d, err = zx.Stat(fs, mv.Child)
			if err != nil {
				t.Fatalf("stat %s: %s", mv.Child, err)
			}
			if d["path"] != mv.Child {
				t.Fatalf("%s: bad path %s", mv.Child, d["path"])
			}
		}
		paths := []string{mv.From, mv.To, path.Dir(mv.From), path.Dir(mv.To)}
		for _, p := range paths {
			d, err := zx.Stat(fs, mv.To)
			if err != nil {
				t.Fatalf("stat %s: %s", p, err)
			}
			chkdirs(t, fs, d, false)
		}
	}
	printf("\n")
}
Пример #3
0
func (c *FileInfo) syncData() {
	d, err := zx.Stat(c.lfs, c.path)
	if err != nil {
		c.dprintf("sync %s: %s\n", c.path, err)
		c.invalid()
		return
	}
	if c.wasdel {
		if c.path == "" || c.path == "/" {
			panic("remove all /")
		}
		<-c.rfs.RemoveAll(c.path) // and ignore errors
	}
	delete(d, "Rtime")
	delete(d, "Cache")
	d["Mode"] = d["mode"]
	if d["type"] == "d" {
		err = <-c.rfs.Mkdir(c.path, d)
	} else {
		datc := c.lfs.Get(c.path, 0, zx.All, "")
		rc := c.rfs.Put(c.path, d, 0, datc, "")
		<-rc
		err = cerror(rc)
	}
	c.state = CClean
	if err != nil {
		c.dprintf("%s: sync meta: %s\n", c.path, err)
		c.invalid()
	}
	c.wasdel = false
}
Пример #4
0
func authfs(t Fataler, xfs zx.Tree) zx.RWTree {
	d, err := zx.Stat(xfs, "/d")
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	printf("d is: %s\n", d)
	uid := d["Uid"]
	if uid == "" {
		t.Fatalf("no uid")
	}
	gid := d["Gid"]
	if uid == "" {
		t.Fatalf("no gid")
	}
	wuid := d["Wuid"]
	if wuid == "" {
		t.Fatalf("no wuid")
	}
	ai := &auth.Info{
		Uid: uid, SpeaksFor: uid, Ok: true,
		Gids: map[string]bool{"gid1": true, "gid2": true},
	}
	if gid != uid {
		ai.Gids[gid] = true
	}
	return authfor(t, xfs, ai)
}
Пример #5
0
// If ln is "path addr" and addr is of the form
// net ! addr ! proto ! tree ! path
// or
// /one/path
// the dial the tree and walk to the path.
func specialForm(ln string) (string, zx.Dir) {
	if len(ln)==0 || ln[0]!='/' {
		return "", nil
	}
	toks := strings.Fields(ln)
	if len(toks)!=2 || len(toks[0])==0 || len(toks[1])==0 {
		return "", nil
	}
	p, addr := toks[0], toks[1]
	if addr[0] == '/' {
		addr = "*!*!lfs!main!" + addr
	}
	atoks := strings.SplitN(addr, "!", -1)
	if len(atoks) < 2 {
		return "", nil
	}
	t, err := rfs.Import(addr)
	if err != nil {
		dbg.Warn("ns: %s: import: %s", ln, err)
		return "", nil
	}
	path := "/"
	if len(atoks)>=5 && atoks[2]!="lfs" {
		path = atoks[4]
	}
	d, err := zx.Stat(t, path)
	if err != nil {
		dbg.Warn("ns: %s: stat: %s", ln, err)
		return "", nil
	}
	return p, d
}
Пример #6
0
func nostat(t Fataler, fs zx.Tree, p string) bool {
	_, err := zx.Stat(fs, p)
	if err == nil {
		t.Logf("could stat %s", p)
		return false
	}
	return true
}
Пример #7
0
/*
	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
}
Пример #8
0
func DirSizes(t Fataler, fss ...zx.Tree) {
	for _, fs := range fss {
		rf, err := zx.Stat(fs, "/")
		if err != nil {
			t.Fatalf("stat: %s", err)
		}
		chkdirs(t, fs, rf, true)
	}
}
Пример #9
0
func Stats(t Fataler, fs zx.Fs) {
	ds := []zx.Dir{}
	for _, p := range AllFiles {
		dc := fs.Stat(p)
		d := <-dc
		if err := cerror(dc); err != nil {
			t.Fatalf("stat %s: %s", p, err)
		}
		ds = append(ds, d)
	}

	for _, d := range ds {
		Printf("%s\n", d.Fmt())
	}
	Printf("\n")
	for _, d := range ds {
		Printf("%s\n", d.LongFmt())
	}
	Printf("\n")
	for i, d := range ds {
		s := d.TestFmt()
		Printf("`%s`,\n", s)
		if s != stats[i] && !strings.HasPrefix(s, stats[i]) {
			Printf("not `%s`,\n", stats[i])
			t.Fatalf("bad stat")
		}
	}
	Printf("\n")

	for _, p := range NotThere {
		dc := fs.Stat(p)
		d := <-dc
		if d != nil {
			t.Fatalf("%s is there", p)
		}
		if !zx.IsNotExist(cerror(dc)) {
			Printf("bad err %v\n", cerror(dc))
		}
	}

	for i, p := range BadPaths {
		d, err := zx.Stat(fs, p)
		if d != nil {
			Printf("%s\n", d.TestFmt())
		} else {
			Printf("err %s\n", err)
		}
		if i == 0 && d["path"] != "/" {
			t.Fatalf("bad bad path")
		}
		if i > 0 && d != nil {
			t.Fatalf("bad bad path")
		}
	}
}
Пример #10
0
func mkns(t *testing.T, d bool) *Tree {
	lfs1, lfs2 := mktrees(t)

	ns := New()
	ns.Debug = d
	ns.DebugFind = d

	root1, err := zx.Stat(lfs1, "/")
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	err = <-ns.Mount("/", root1, Repl)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}

	root2, err := zx.Stat(lfs2, "/")
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	err = <-ns.Mount("/a/b", root2, Repl)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	d1 := zx.Dir{"path": "x", "name": "x", "proto": "p1"}
	err = <-ns.Mount("/d", d1, Before)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	d2 := zx.Dir{"path": "x", "name": "x", "proto": "p2"}
	err = <-ns.Mount("/d", d2, After)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	err = <-ns.Mount("/d", d2, After)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	printf("ns is `%s`\n", ns)
	return ns
}
Пример #11
0
// Compute changes for fs1 to become like fs2 and send them through the
// returned chan.
// If no path is given, "/" is used.
func Diff(fs1, fs2 zx.Getter, path ...string) <-chan zx.Chg {
	p := "/"
	if len(path) > 0 {
		p = path[0]
	}
	rc := make(chan zx.Chg)
	// TODO: this should use find instead of stat+get
	go func() {
		var d1, d2 zx.Dir
		var err error
		d1, err = zx.Stat(fs1, p)
		if err == nil {
			d2, err = zx.Stat(fs2, p)
		}
		if err == nil {
			err = diff(d1, d2, fs1, fs2, rc)
		}
		close(rc, err)
	}()
	return rc
}
Пример #12
0
// no locks, used only at init time
func (t *Fs) reload() {
	d, err := zx.Stat(t.lfs, "/")
	if err != nil {
		dbg.Warn("%s: reload: %s", t.name, err)
		return
	}
	ud := d.UsrAttrs()
	ud["Sum"] = d["Sum"]
	for k, v := range ud {
		t.root.d[k] = v
	}
	t.reloadChild(t.root)
}
Пример #13
0
func mkmfstrees(t *testing.T) (zx.RWTree, zx.RWTree) {
	lfs1, err := mfs.New(tdir)
	if err != nil {
		t.Fatalf("mfs: %s", err)
	}
	fstest.MkZXTree(t, lfs1)
	d, err := zx.Stat(lfs1, "/")
	if err != nil {
		t.Fatalf("mfs: %s", err)
	}
	zx.RegisterProcTree(lfs1, d["tpath"])
	lfs1.Dbg = testing.Verbose() && moreverb
	return lfs1, lfs1
}
Пример #14
0
func (tf *File) Seek(off int64, whence int) (int64, error) {
	switch whence {
	case 0:
		tf.off = off
	case 1:
		tf.off += off
	case 2:
		st, err := zx.Stat(tf.t, tf.path)
		if err != nil {
			return 0, err
		}
		tf.off = st.Int64("size") + off
	}
	return tf.off, nil
}
Пример #15
0
func chkok(fs zx.Tree, attr string) error {
	d, err := zx.Stat(fs, "/")
	if err != nil  {
		return fmt.Errorf("%s: %s", fs.Name(), err)
	}
	rwfs, ok := fs.(zx.RWTree)
	if !ok {
		return nil
	}
	if err := <-rwfs.Wstat("/", zx.Dir{attr: "666"}); err != nil {
		return err
	}
	d, err = zx.Stat(fs, "/")
	if err != nil  {
		return fmt.Errorf("%s: %s", fs.Name(), err)
	}
	if d[attr] != "666" {
		return fmt.Errorf("%s: does not preserve %s", fs.Name(), attr)
	}
	if err := <-rwfs.Wstat("/", zx.Dir{attr: ""}); err != nil {
		return err
	}
	return nil
}
Пример #16
0
// zx.Stat using the app ns and dot.
func Stat(path string) (zx.Dir, error) {
	if len(path) > 0 && path[0] == '#' {
		_, err := app.IOarg(path)
		if err != nil {
			return nil, fmt.Errorf("%s: %s", path, err)
		}
		d := zx.Dir{"path": path, "name": path,
			"upath": path, "type":"c"}
		return d, nil
	}
	path = app.AbsPath(path)
	_, trs, spaths, err := app.ResolveTree(path)
	if err != nil {
		return nil, err
	}
	return zx.Stat(trs[0], spaths[0])
}
Пример #17
0
func runTest(t *testing.T, fn fstest.TestFunc) {
	os.Args[0] = "rzx.test"
	fstest.Verb = testing.Verbose()
	ccfg, err := net.TLSCfg("/Users/nemo/.ssh/client")
	if err != nil {
		t.Logf("no certs found, no tls conn")
	}
	scfg, err := net.TLSCfg("/Users/nemo/.ssh/server")
	if err != nil || ccfg == nil {
		ccfg = nil
		scfg = nil
		t.Logf("no certs found, no tls conn")
	}
	_, _ = scfg, ccfg
	fstest.MkTree(t, tdir)
	defer os.RemoveAll(tdir)
	lfs, err := zux.NewZX(tdir)
	if err != nil {
		t.Fatal(err)
	}
	defer lfs.Sync()

	cfs, err := New(lfs)
	if err != nil {
		t.Fatal(err)
	}
	defer cfs.Close()
	cfs.Debug = testing.Verbose()
	lfs.Debug = testing.Verbose()
	cfs.Flags.Set("rfsdebug", cfs.Debug)
	cfs.Flags.Set("cachedebug", cfs.Debug)
	if fn != nil {
		fn(t, cfs)
	} else {
		d, err := zx.Stat(cfs, "/")
		if err != nil {
			t.Fatalf("stat /: %v", err)
		}
		t.Logf("/ stat is %s\n", d.TestFmt())
	}
	if cfs.Debug {
		cfs.c.dump()
	}
}
Пример #18
0
func EqFiles(t Fataler, path string, fss ...zx.Tree) {
	dirs := []zx.Dir{}
	nerrs := 0
	for _, fs := range fss {
		d, err := zx.Stat(fs, path)
		if err != nil {
			printf("%s: not there: %s\n", fs.Name(), err)
			nerrs++
			continue
		}
		printf("%s: %s\n", fs.Name(), d.LongTestFmt())
		dirs = append(dirs, d)
	}
	if nerrs > 0 {
		if nerrs != len(fss) {
			t.Fatalf("exists only in some")
		}
		return
	}
	for i := 1; i < len(dirs); i++ {
		if dirs[i].TestFmt() != dirs[0].TestFmt() {
			t.Logf("dir%d %s\n", i, dirs[i].TestFmt())
			t.Logf("dir0 %s\n", dirs[0].TestFmt())
			t.Fatalf("dirs do not match")
		}
	}
	if dirs[0]["type"] == "d" {
		return
	}
	datas := [][]byte{}
	for _, fs := range fss {
		dat, err := zx.GetAll(fs, path)
		if err != nil {
			t.Fatalf("%s: %s: %s", fs, path, err)
		}
		datas = append(datas, dat)
	}
	for i := 1; i < len(datas); i++ {
		if bytes.Compare(datas[i], datas[0]) != 0 {
			t.Fatalf("data differs")
		}
	}

}
Пример #19
0
func (c *FileInfo) syncMeta() {
	d, err := zx.Stat(c.lfs, c.path)
	if err == nil {
		d = d.UsrAttrs()
		delete(d, "mtime")
		delete(d, "size")
		delete(d, "Rtime")
		delete(d, "Cache")
		d["Mode"] = d["mode"]
		err = <-c.rfs.Wstat(c.path, d)
	}
	if err != nil {
		c.dprintf("%s: sync meta: %s\n", c.path, err)
		c.invalid()
	} else if c.state == CUnreadMeta {
		c.state = CUnread
	} else {
		c.state = CClean
	}
	c.wasdel = false
}
Пример #20
0
func stat(t Fataler, fs zx.Tree, p, res string) bool {
	d, err := zx.Stat(fs, p)
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	s := fmt.Sprintf("%s %s %s %s", d["mode"], d["Uid"], d["Gid"], d["Wuid"])
	us := strings.Replace(s, dbg.Usr, "nemo", -1)
	printf("%s: %s\n", p, us)

	// At least lfs does not update Wuid for directories, but that's ok
	if d["type"] == "d" && res != "" {
		toks := strings.Fields(res)
		res = strings.Join(toks[:len(toks)-1], " ")
		s = fmt.Sprintf("%s %s %s", d["mode"], d["Uid"], d["Gid"])
		us = strings.Replace(s, dbg.Usr, "nemo", -1)
	}
	if res != "" && us != res {
		t.Logf("wrong stat for %s <%s>", p, us)
		return false
	}
	return true
}
Пример #21
0
func attr(aname string, v1 value) (value, error) {
	fname, ok := v1.(string)
	if !ok {
		return nil, errors.New("not a file name")
	}
	fname, _ = filepath.Abs(fname)
	_, ts, ns, err := cmd.ResolveTree(fname)
	if err != nil {
		panic(err)
	}
	t := ts[0]
	spath := ns[0]
	d, err := zx.Stat(t, spath)
	if err != nil {
		panic(err)
	}
	if aname == "r" {
		return d.Int("mode")&0444 != 0, nil
	}
	if aname == "w" {
		return d.Int("mode")&0222 != 0, nil
	}
	if aname == "x" {
		return d.Int("mode")&0111 != 0, nil
	}
	if aname == "mode" {
		return fmt.Sprintf("0%o", d.Int("mode")&0777), nil
	}
	if aname == "size" {
		return uint64(d.Int64("size")), nil
	}
	if aname == "mtime" {
		return d.Time("mtime"), nil
	}
	return d[aname], nil
}
Пример #22
0
func mkrns(t *testing.T, d bool) *Tree {
	fstest.MkTree(t, tdir)
	lfs1, err := lfs.New(tdir, tdir, lfs.RW)
	if err != nil {
		t.Fatalf("lfs: %s", err)
	}
	hs, hc := fifo.NewChanHandler()
	s := fifo.New("rfs", "rfs", hs)
	if err = s.Serve(); err != nil {
		t.Fatalf("%s", err)
	}
	go func() {
		for c := range hc {
			ai, err := auth.AtServer(*c, "", "zx", "finder")
			if err!=nil && err!=auth.ErrDisabled {
				dbg.Warn("auth %s: %s\n", c.Tag, err)
				close(c.In, err)
				close(c.Out, err)
				return
			}
			rfs.Serve("srv", *c, ai, rfs.RW, lfs1)
		}
	}()
	rfs1, err := rfs.Import("fifo!*!rfs")
	if err != nil {
		t.Fatalf("lfs: %s", err)
	}
	ns := New()

	ns.Debug = d
	ns.DebugFind = d

	root1, err := zx.Stat(lfs1, "/")
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	err = <-ns.Mount("/", root1, Repl)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}

	root2, err := zx.Stat(rfs1, "/")
	if err != nil {
		t.Fatalf("stat: %s", err)
	}
	err = <-ns.Mount("/a/b", root2, Repl)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	d1 := zx.Dir{"path": "x", "name": "x", "proto": "p1"}
	err = <-ns.Mount("/d", d1, Before)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	d2 := zx.Dir{"path": "x", "name": "x", "proto": "p2"}
	err = <-ns.Mount("/d", d2, After)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	err = <-ns.Mount("/d", d2, After)
	if err != nil {
		t.Fatalf("mount: %s", err)
	}
	printf("ns is `%s`\n", ns)
	return ns
}
Пример #23
0
func Puts(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	rd, err := zx.Stat(fs, "/")
	if err != nil {
		t.Fatalf("root stat %s", err)
	}
	printf("root %s\n", rd.TestFmt())
	for z := 0; z < Repeats; z++ {
	Loop:
		for nfi, nf := range PutTests {
			dc := make(chan []byte, 1)
			nf.data = make([]byte, 0, 32*1024)
			xd := nf.Dir.Dup()
			printf("put %s %v\n", nf.Path, xd)
			nn := nfi + 1
			if nf.N != 0 {
				nn = 2
			}
			xc := fs.Put(nf.Path, xd, 0, dc, "")
			for i := 0; i < 1000*nn; i++ {
				msg := []byte(fmt.Sprintf("hi %s %d\n", nf.Path, i))
				nf.data = append(nf.data, msg...)
				if ok := dc <- msg; !ok {
					err := cerror(dc)
					if !nf.Fails {
						t.Fatalf("%s: %s\n", nf.Path, err)
					}
					continue Loop
				}
			}
			printf("put %s: sent %d bytes\n", nf.Path, len(nf.data))
			close(dc)
			xd = <-xc
			if nf.Fails {
				if xd!=nil || cerror(xc)==nil {
					t.Fatalf("%s: didn't fail", nf.Path)
				}
				continue
			}
			if xd==nil || cerror(xc)!=nil {
				t.Fatalf("%s: %s\n", nf.Path, cerror(xc))
			}
			got := xd.TestFmt()
			printf("got %s\n", got)
			if nf.Dir["mtime"] != "" {
				got += " mtime " + xd["mtime"]
			}
			if got != nf.Res {
				t.Logf("expected %s\n", nf.Res)
				t.Logf("got %s\n", got)
				t.Fatalf("%s: bad dir output", nf.Path)
			}
			fd, err := zx.Stat(fs, nf.Path)
			if err != nil {
				t.Fatalf("stat: %s", err)
			}
			got = fd.TestFmt()
			if nf.Dir["mtime"] != "" {
				got += " mtime " + fd["mtime"]
			}
			if nf.Dir["X"] != "" {
				got += " X " + fd["X"]
			}
			printf("after put: %s\n", got)
			if nf.Rdir != "" && nf.Rdir != got {
				t.Logf("expected <%s>", nf.Rdir)
				t.Fatalf("got <%s>", got)
			}
			for _, fs := range fss {
				dat, err := zx.GetAll(fs, nf.Path)
				if err != nil {
					t.Fatalf("couldn't get: %s", err)
				}
				if nf.N != 0 && len(dat) != nf.N {
					t.Fatalf("bad output size: %d", len(dat))
				}
				if nf.N != 0 && len(dat) > len(nf.data) {
					dat = dat[:len(nf.data)]
				}
				if nf.N != 0 && len(dat) < len(nf.data) {
					nf.data = nf.data[:len(dat)]
				}
				if string(dat) != string(nf.data) {
					t.Fatalf("bad data %d vs %d bytes", len(dat), len(nf.data))
				}
			}
		}
	}
}


func GetCtl(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	vals := []bool{false, true}
	outs := []string{"debug off", "debug on"}
	for i, v := range vals {
		d := fs.(zx.Debugger).Debug()
		*d = v
		printf("get ctl: (debug %v)\n", v)
		dat, err := zx.GetAll(fs, "/Ctl")
		if err != nil {
			t.Fatalf("get /ctl: %s", err)
		}
		ctls := string(dat)
		printf("<%s>\n\n", ctls)
		if !strings.Contains(ctls, outs[i]) {
			t.Fatalf("wrong ctl output")
		}
	}
}

func PutCtl(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	vals := []bool{false, true, false, true}
	ins := []string{"nodebug", "debug", "debug off", "debug on"}
	outs := []string{"debug off", "debug on", "debug off", "debug on"}
	for i, v := range vals {
		printf("put ctl: (debug %v)\n", v)
		err := zx.PutAll(fs, "/Ctl", nil, []byte(ins[i]))
		if err != nil {
			t.Fatalf("put /ctl: %s", err)
		}
		printf("get ctl: (debug %v)\n", v)
		dat, err := zx.GetAll(fs, "/Ctl")
		if err != nil {
			t.Fatalf("get /ctl: %s", err)
		}
		ctls := string(dat)
		printf("<%s>\n\n", ctls)
		if !strings.Contains(ctls, outs[i]) {
			t.Fatalf("wrong ctl output")
		}
	}
	err := zx.PutAll(fs, "/Ctl", nil, []byte("bad ctl request"))
	if err == nil {
		t.Fatalf("bad put did not fail")
	}
	printf("put sts %s\n", err)
}


func PutsBench(b *testing.B, xfs zx.Tree) {
	fs := xfs.(zx.RWTree)
	b.StopTimer()
	var buf [1024]byte
	copy(buf[0:], "hola")
	<-fs.Remove("/nfb")
	b.StartTimer()
	for bi := 0; bi < b.N; bi++ {
		dc := make(chan []byte)
		xc := fs.Put("/nfb", zx.Dir{"mode": "0644"}, 0, dc, "")
		for i := 0; i < 128; i++ {
			if ok := dc <- buf[:]; !ok {
				b.Fatalf("put failed")
			}
		}
		close(dc)
		if len(<-xc) == 0 {
			b.Fatalf("put failed")
		}
	}
}

var (
	MkdirPaths    = []string{"/nd", "/nd/nd2", "/nd/nd22", "/nd/nd23", "/nd3"}
	BadMkdirPaths = []string{"/", "/nd", "/a"}
)

func Mkdirs(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	for i := 0; i < Repeats; i++ {
		for _, p := range MkdirPaths {
			printf("mkdir %s\n", p)
			ec := fs.Mkdir(p, zx.Dir{"mode": "0750"})
			err := <-ec
			if i>0 && err==nil {
				t.Fatalf("could re-mkdir %s", p)
			}
			if i==0 && err!=nil {
				t.Fatalf("%s: %s", p, err)
			}
			for _, fs := range fss {
				d, err := zx.Stat(fs, p)
				if err!=nil || d["type"]!="d" || d["mode"]!="0750" {
					t.Fatalf("mkdir not there %v %v", err, d)
				}
			}
		}
		for _, p := range BadMkdirPaths {
			printf("mkdir %s\n", p)
			ec := fs.Mkdir(p, zx.Dir{"mode": "0750"})
			err := <-ec
			if err == nil {
				t.Fatalf("mkdir %s worked", p)
			}
		}
	}
}

var (
	RemovePaths    = []string{"/d", "/e/f", "/e", "/a/a2"}
	BadRemovePaths = []string{"/", "/xxx", "/a"}
)

func Removes(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	for i := 0; i < Repeats; i++ {
		for _, p := range RemovePaths {
			printf("remove %s\n", p)
			ec := fs.Remove(p)
			err := <-ec
			if i>0 && err==nil {
				t.Fatalf("could re-remove %s", p)
			}
			if i==0 && err!=nil {
				t.Fatalf("%s: %s", p, err)
			}
			for _, fs := range fss {
				d, err := zx.Stat(fs, p)
				if err==nil || d!=nil {
					t.Fatalf("%s still there", p)
				}
			}
		}
		for _, p := range BadRemovePaths {
			ec := fs.Remove(p)
			err := <-ec
			if err == nil {
				t.Fatalf("remove %s worked", p)
			}
		}
	}
}

func MkdirRemoveBench(b *testing.B, xfs zx.Tree) {
	fs := xfs.(zx.RWTree)
	b.StopTimer()
	<-fs.Remove("/mrb")
	b.StartTimer()
	for bi := 0; bi < b.N; bi++ {
		xc := fs.Mkdir("/mrb", zx.Dir{"mode": "0755"})
		if <-xc != nil {
			b.Fatalf("mkdir failed")
		}
		xc = fs.Remove("/mrb")
		if <-xc != nil {
			b.Fatalf("remove failed")
		}
	}
}

type WstatTest  {
	Path  string
	Dir   zx.Dir
	AppDir bool
	Res   string
	Fails bool
}

var WstatTests = []WstatTest{
	{
		Path: "/d",
		Dir:  zx.Dir{"mode": "0704", "foo": "bar"},
		Res:  `path /d name d type d mode 0704 size 0`,
	},
	{
		Path: "/e/f",
		Dir:  zx.Dir{"mode": "0704", "foo": "bar"},
		Res:  `path /e/f name f type d mode 0704 size 0`,
	},
	{
		Path: "/e",
		Dir:  zx.Dir{"mode": "0704", "foo": "bar"},
		Res:  `path /e name e type d mode 0704 size 1`,
	},
	{
		Path: "/a/a2",
		Dir:  zx.Dir{"mode": "0704", "foo": "bar"},
		Res:  `path /a/a2 name a2 type - mode 0704 size 21418`,
	},
	{
		Path: "/",
		Dir:  zx.Dir{"mode": "0704", "foo": "bar"},
		Res:  `path / name / type d mode 0704 size 0`,
	},
	{
		Path:  "/xxx",
		Dir:   zx.Dir{"mode": "0704", "foo": "bar"},
		Fails: true,
	},
	{
		Path:  "/a/xxx",
		Dir:   zx.Dir{"mode": "0704", "foo": "bar"},
		Fails: true,
	},
	{
		Path:  "/dx",
		Dir:   zx.Dir{"mode": "0704", "foo": "bar"},
		Fails: true,
	},
}

func Wstats(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	for i := 0; i < Repeats; i++ {
		for _, f := range WstatTests {
			printf("wstat %s %v\n", f.Path, f.Dir)
			ec := fs.Wstat(f.Path, f.Dir)
			err := <-ec
			if f.Fails {
				if err == nil {
					t.Fatalf("%s didn't fail", f.Path)
				}
				continue
			}
			if !f.Fails && err!=nil {
				t.Fatalf("%s: %s", f.Path, err)
			}
			for _, fs := range fss {
				d, err := zx.Stat(fs, f.Path)
				if err != nil {
					t.Fatalf("stat %s: %s", f.Path, err)
				}
				if d["path"] == "/" {
					d["size"] = "0" // ctl, chg
				}
				if d.TestFmt() != f.Res {
					t.Logf("for %s\n", fs.Name())
					t.Logf("expected %s\n", f.Res)
					t.Logf("got %s\n", d.TestFmt())
					t.Fatalf("stat %s: didn't wstat it", f.Path)
				}
			}
		}
	}
}

var UsrWstatTests = []WstatTest{
	// extra bits in mode
	{
		Path: "/a",
		Dir:  zx.Dir{"mode": "07755"},
		Res: `path /a name a type d mode 0755 size 3 Gid nemo Uid nemo Wuid nemo`,
	},
	// changing size in a dir is ignored if writing existing attributes.
	{
		Path: "/a",
		Dir:  zx.Dir{"size": "5"},
		AppDir: true,
		Res: `path /a name a type d mode 0755 size 3 Gid nemo Uid nemo Wuid nemo`,
	},
	// writing a non  user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"foo": "bar"},
		Fails: true,
	},
	// writing a ignored non  user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"mtime": "0", "foo": "bar"},
		Res: `path /a name a type d mode 0755 size 3 Gid nemo Uid nemo Wuid nemo`,
	},
	// Adding a user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"Dir": "X"},
		Res: `path /a name a type d mode 0755 size 3 Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Same, using the previous dir
	{
		Path: "/a",
		Dir:  zx.Dir{"Dir": "X"},
		AppDir: true,
		Res: `path /a name a type d mode 0755 size 3 Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Adding a two user attributes
	{
		Path: "/a",
		Dir:  zx.Dir{"Dir": "X", "Abc": "A"},
		Res: `path /a name a type d mode 0755 size 3 Abc A Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Removing a non existing user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"Non": ""},
		Res: `path /a name a type d mode 0755 size 3 Abc A Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Rewriting a user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"Abc": "B"},
		Res: `path /a name a type d mode 0755 size 3 Abc B Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Removing a user attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"Abc": ""},
		Res: `path /a name a type d mode 0755 size 3 Dir X Gid nemo Uid nemo Wuid nemo`,
	},
	// Type change
	{
		Path: "/a",
		Dir:  zx.Dir{"type": "x"},
		Fails: true,
	},
	// Removing a sys attribute
	{
		Path: "/a",
		Dir:  zx.Dir{"type": "", "Dir": "X"},
		Fails: true,
	},
	// Trying to change size
	{
		Path: "/a",
		Dir:  zx.Dir{"size": "55"},
		Fails: true,
	},
	// Bad path
	{
		Path: "2",
		Dir:  zx.Dir{"size": "55"},
		Fails: true,
	},
	// Truncating a file
	{
		Path: "/2",
		Dir:  zx.Dir{"size": "55"},
		Res: `path /2 name 2 type - mode 0644 size 55 Gid nemo Uid nemo Wuid nemo`,
	},
}

func UsrWstats(t Fataler, fss ...zx.Tree) {
	if len(fss) == 0 {
		t.Fatalf("no fs given")
	}
	fs := fss[0].(zx.RWTree)
	for i := 0; i < 1; i++ {
		for _, f := range UsrWstatTests {
			d := f.Dir.Dup()
			if f.AppDir {
				od, err := zx.Stat(fs, f.Path)
				if err != nil {
					t.Fatalf("stat %s: %s", f.Path, err)
				}
				for k, v := range d {
					od[k] = v
				}
				d = od
			}
			printf("wstat %s %s\n", f.Path, d.LongTestFmt())
			ec := fs.Wstat(f.Path, d)
			err := <-ec
			if f.Fails {
				if err == nil {
					t.Fatalf("%s didn't fail", f.Path)
				}
				continue
			}
			if !f.Fails && err!=nil {
				t.Fatalf("%s: %s", f.Path, err)
			}
			for _, fs := range fss {
				d, err := zx.Stat(fs, f.Path)
				if err != nil {
					t.Fatalf("stat %s: %s", f.Path, err)
				}
				printf("result %s %s\n", f.Path, d.LongTestFmt())
				if d["foo"] != "" {
					t.Fatalf("could write foo")
				}
				if f.Res == "" {
					continue
				}
				if d["path"] == "/" {
					d["size"] = "0" // ctl, chg
				}
				delete(d, "Sum")
				ds := strings.Replace(d.LongTestFmt(), "nemo", "none", -1)
				ds2 := strings.Replace(f.Res, "nemo", "none", -1)
				if ds != ds2 {
					t.Logf("for fs %s\n", fs.Name())
					t.Logf("expected %s\n", f.Res)
					t.Logf("got %s\n", d.LongTestFmt())
					t.Fatalf("stat %s: didn't wstat it", f.Path)
				}
			}
		}
	}
}

func WstatBench(b *testing.B, xfs zx.Tree) {
	fs := xfs.(zx.RWTree)
	for bi := 0; bi < b.N; bi++ {
		xc := <-fs.Wstat("/e", zx.Dir{"mode": "0755"})
		if xc != nil {
			b.Fatalf("wstat failed")
		}
	}
}

var SendOuts = []string{
	`/`,
	`path /1 name 1 type - mode 0644 size 0`,
	`path /2 name 2 type - mode 0644 size 31658`,
	`path /a name a type d mode 0755 size 3`,
	`path /a/a1 name a1 type - mode 0644 size 10154`,
	`path /a/a2 name a2 type - mode 0644 size 21418`,
	`path /a/b name b type d mode 0755 size 1`,
	`path /a/b/c name c type d mode 0755 size 1`,
	`path /a/b/c/c3 name c3 type - mode 0644 size 44970`,
	`path /d name d type d mode 0755 size 0`,
	`path /e name e type d mode 0755 size 1`,
	`path /e/f name f type d mode 0755 size 0`,
}

func SendRecv(t Fataler, sfs, rfs zx.RWTree) {
	dc := make(chan []byte)
	rf, err := zx.Stat(sfs, "/")
	if err!=nil || rf==nil {
		t.Fatalf("stat: %s", err)
	}
	zx.DebugSend = testing.Verbose()
	go func() {
		err := zx.Send(sfs, rf, dc)
		close(dc, err)
	}()
	err = zx.Recv(rfs, dc)
	if cerror(dc) != nil {
		t.Logf("send err %s", cerror(dc))
	}
	if err != nil {
		t.Fatalf("recv: %s", err)
	}
	err = cerror(dc)
	if err != nil {
		t.Fatalf("send: %s", err)
	}
	fc := rfs.Find("/", "", "/", "/", 0)
	tot := 0
	outs := []string{}
	for d := range fc {
		printf("\t`%s`,\n", d.LongTestFmt())
		if d["path"] == "/" {
			outs = append(outs, "/")
			tot++
			continue
		}
		if d["path"] == "/" {
			d["size"] = "0" // get rid of ctl, chg
		}
		if d["path"]=="/Ctl" || d["path"]=="/Chg" {
			continue
		}
		tot++
		outs = append(outs, d.TestFmt())
	}
	if tot != 12 {
		t.Fatalf("bad find tot: got %d", tot)
	}
	if strings.Join(outs, "\n") != strings.Join(SendOuts, "\n") {
		t.Fatalf("bad received tree")
	}
}

// Check out if fs.Dump() is the same for all trees
func SameDump(t Fataler, fss ...zx.Tree) {
	old := ""
	oname := ""
	nname := ""
	for _, tfs := range fss {
		var buf bytes.Buffer
		fs, ok := tfs.(zx.Dumper)
		if !ok {
			continue
		}
		fs.Dump(&buf)
		ns := buf.String()
		toks := strings.SplitN(ns, "\n", 2)
		if len(toks) > 1 {
			ns = toks[1]
			nname = toks[0]
		}
		if old == "" {
			old = ns
			oname = nname
		} else if old != ns {
			t.Logf("%s\n<%s>\n", oname, old)
			t.Logf("%s\n<%s>\n", nname, ns)
			i := 0
			for i < len(old) && i < len(ns) {
				if old[i] != ns[i] {
					break
				}
				i++
			}
			t.Logf("suffix1 <%s>\n", old[i:])
			t.Logf("suffix2 <%s>\n", ns[i:])
			t.Fatalf("trees do not match")
		}
	}
}
Пример #24
0
func rstat(t Fataler, fs zx.RWTree, fname string) {
	zx.Stat(fs, fname)
}
Пример #25
0
func dump(dir string, t zx.Tree, ec chan bool) {
	defer func() {
		ec <- true
	}()
	name := t.Name()
	data := zx.Path(dir, "data")
	doskip := Skip
	for {
		if doskip {
			waitDumpTime(name)
			doskip = false
			continue
		}
		dbg.Warn("snap %s...", name)
		if err := os.MkdirAll(data, 0750); err != nil {
			dbg.Warn("%s: %s", data, err)
			return
		}
		rd, err := zx.Stat(t, "/")
		if err != nil {
			dbg.Warn("%s: %s", name, err)
			continue
		}
		// make sure it's not empty
		ds, err := zx.GetDir(t, "/")
		if err != nil {
			dbg.Warn("%s: %s", name, err)
			continue
		}
		if len(ds) == 0 {
			dbg.Warn("%s: file system is empty. ignored.", name)
			continue
		}
		s, err := dumpDir(data, name, zx.File{t, rd})
		if err != nil {
			dbg.Warn("%s: %s", name, err)
		}
		ts := time.Now().Format("2006/0102")
		tree := strings.Replace(name, "/", ".", -1)
		tspath0 := zx.Path(dir, tree, ts)
		os.MkdirAll(path.Dir(tspath0), 0755)
		spath := zx.Path(data, s)
		tspath := tspath0
		for i := 1; ; i++ {
			fi, _ := os.Stat(tspath)
			if fi == nil {
				break
			}
			tspath = fmt.Sprintf("%s.%d", tspath0, i)
		}
		os.MkdirAll(path.Dir(tspath), 0755)
		if err := os.Symlink(spath, tspath); err != nil {
			dbg.Warn("%s: %s", name, err)
		}
		dbg.Warn("snap %s %s", tspath, s)
		if Once {
			break
		}
		waitDumpTime(name)
	}
}