Пример #1
0
func Mkdirs(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		for _, dp := range MkdirPaths {
			printf("mkdir %s\n", dp)
			p := zx.Path(d, dp)
			if err := os.Mkdir(p, 0750); err != nil {
				t.Fatalf("mkdir %s: %s", p, err)
			}
			fi, err := os.Stat(p)
			if err != nil {
				t.Fatalf("didn't stat: %s", err)
			}
			if !fi.IsDir() {
				t.Fatalf("didn't create a dir")
			}
			if fi.Mode().String() != "drwxr-x---" {
				t.Fatalf("bad dir mode")
			}
		}
		for _, dp := range BadMkdirPaths {
			printf("mkdir %s\n", dp)
			p := zx.Path(d, dp)
			if err := os.Mkdir(p, 0750); err == nil {
				t.Fatalf("mkdir %s: didn't fail")
			}
		}
	}
}
Пример #2
0
func diff(rc chan<- string, fn string, mtime bool, dirs ...string) {
	d0 := dirs[0]
	dirs = dirs[1:]
	for _, di := range dirs {
		p0 := zx.Path(d0, fn)
		pi := zx.Path(di, fn)
		s := diff1(p0, pi, fn != "/", mtime)
		if s != "" {
			rc <- fmt.Sprintf("%s: chg %s %s", di, fn, s)
		}
		c0 := Children(p0)
		c1 := Children(pi)
		if len(c0) ==0 && len(c1) == 0 {
			continue
		}
		for _, c := range c0 {
			cf := zx.Path(fn, c)
			if !member(c, c1) {
				rc <- fmt.Sprintf("%s: del %s", di, cf)
				continue
			}
			diff(rc, cf, mtime, d0, di)
		}
		for _, c := range c1 {
			if !member(c, c0) {
				cf := zx.Path(fn, c)
				rc <- fmt.Sprintf("%s: add %s", di, cf)
			}
		}
	}
}
Пример #3
0
// 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
}
Пример #4
0
// make sure paths are ok in children after a move
func (f *mFile) moved() {
	f.mlk.Lock()
	fpath := f.d["path"]
	fspath := f.d["spath"]
	f.mlk.Unlock()
	f.clk.Lock()
	defer f.clk.Unlock()
	for _, cs := range f.child {
		cs.mlk.Lock()
		cs.d["path"] = zx.Path(fpath, cs.name)
		cs.d["spath"] = zx.Path(fspath, cs.name)
		cs.mlk.Unlock()
		cs.moved()
	}
}
Пример #5
0
func All(t Fataler, dirs ...string) {
	diffs, err := Diff(WithoutMtime, dirs...)
	if err != nil {
		t.Fatalf("diff errors")
	}
	if len(diffs) != 0 {
		t.Fatalf("initial diffs")
	}
	Stats(t, dirs...)
	Gets(t, dirs...)
	AsAFile(t, dirs...)
	Puts(t, dirs...)
	Mkdirs(t, dirs...)
	Wstats(t, dirs...)
	Removes(t, dirs...)
	for _, d := range dirs {
		os.Remove(zx.Path(d, "/foo"))
	}
	diffs, err = Diff(WithoutMtime, dirs...)
	if err != nil {
		t.Fatalf("diff errors")
	}
	for _, d := range diffs {
		printf("diff %s\n", d)
	}
	if len(diffs) != 0 {
		t.Fatalf("final diffs")
	}
}
Пример #6
0
func Wstats(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		for _, dp := range WstatTests {
			p := zx.Path(d, dp.Path)
			printf("wstat %s %o %d\n", dp.Path, os.FileMode(dp.Mode)&0777, dp.Mtime)
			if err := os.Chmod(p, dp.Mode); err != nil {
				if dp.Fails {
					continue
				}
				t.Fatalf("chmod: %s", err)
			}
			if dp.Fails {
				t.Fatalf("wstat didn't fail")
			}
			mt := time.Unix(dp.Mtime, 0)
			if err := os.Chtimes(p, mt, mt); err != nil {
				t.Fatalf("chtime: %s", err)
			}
			fi, err := os.Stat(p)
			if err != nil {
				t.Fatalf("stat: %s", err)
			}
			if uint(fi.Mode())&0777 != uint(dp.Mode) {
				t.Fatalf("wrong mode")
			}
			if fi.ModTime().Unix() != dp.Mtime {
				t.Fatalf("wrong mtime")
			}
		}
	}
}
Пример #7
0
func Puts(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		nn := 0
		for _, pt := range PutTests {
			printf("put %s\n", pt.Path)
			p := zx.Path(d, pt.Path)
			// 1. use create
			fd, err := os.Create(p)
			if err != nil && !pt.Fails {
				t.Fatalf("create: %s", err)
			}
			if pt.Fails && err == nil {
				t.Fatalf("create did not fail")
			}
			if pt.Fails {
				continue
			}
			nn++
			var buf bytes.Buffer
			for i := 0; i < 1000*nn; i++ {
				fmt.Fprintf(fd, "hi %s %d\n", pt.Path, i)
				fmt.Fprintf(&buf, "hi %s %d\n", pt.Path, i)
			}
			fd.Close()
			printf("%s: %d bytes\n", pt.Path, buf.Len())
			dat, err := ioutil.ReadFile(p)
			if err != nil {
				t.Fatalf("read: %s", err)
			}
			if bytes.Compare(buf.Bytes(), dat) != 0 {
				t.Fatalf("didn't put the bytes")
			}

			// 2. use openfile with truncate
			fd, err = os.OpenFile(p, os.O_TRUNC|os.O_RDWR, 0644)
			if err != nil {
				t.Fatalf("read: %s", err)
			}
			for i := 0; i < 1000*nn; i++ {
				fmt.Fprintf(fd, "hi %s %d\n", pt.Path, i)
			}
			fd.Close()
			dat, err = ioutil.ReadFile(p)
			if err != nil {
				t.Fatalf("read: %s", err)
			}
			if bytes.Compare(buf.Bytes(), dat) != 0 {
				t.Fatalf("didn't put the bytes")
			}
		}
	}
}
Пример #8
0
// Walk to rid, and return it r/wlocked (unless there's an error) with at least its meta updated.
func (fs *Cfs) walk(rid string, isrlock bool) (f *cFile, left []string, e error) {
	fs.dprintf("walk %s...\n", rid)
	els := zx.Elems(rid)
	left = els
	defer func() {
		if e != nil {
			fs.dprintf("walkerr %s left %v\n", rid, left)
		} else {
			fs.dprintf("walked %s left %v\n", rid, left)
		}
		if e == nil && len(left) > 0 {
			panic("cfs walk: left and no error")
		}
	}()
	path := "/"
	for {
		isr := len(els) > 0 || isrlock
		nf, err := fs.cwalk(path, isr)
		if err != nil {
			return f, left, err
		}
		left = els
		f = nf
		if len(els) > 0 {
			path = zx.Path(path, els[0])
			els = els[1:]
		}
		if len(left) == 0 {
			if err := f.needMeta(isr); err != nil {
				// lock has been released
				if dbg.IsNotExist(err) {
					// discovered in needMeta that the file is gone
					// we raced, so try again
					f, left, err = fs.walk(rid, isrlock)
				}
				return f, left, err
			}
			return f, left, nil
		}
		if err := f.needData(isr, nil); err != nil {
			// lock has been released
			if dbg.IsNotExist(err) {
				// discovered in needMeta that the file is gone
				// we raced, so try again
				f, left, err = fs.walk(rid, isrlock)
			}
			return f, left, err
		}
		if !fs.NoPermCheck && !f.d.CanWalk(fs.ai) {
			f.unlockc(isr)
			return f, left, fmt.Errorf("%s: %s", f, dbg.ErrPerm)
		}
		f.unlockc(isr)
	}
}
Пример #9
0
func main() {
	defer dbg.Exits("")
	os.Args[0] = "zxdump"
	dfltdump := zx.Path(dbg.Home, "dump")
	opts.NewFlag("s", "don't dump right now, wait until next at 5am", &Skip)
	opts.NewFlag("1", "dump once and exit", &Once)
	opts.NewFlag("v", "verbose", &Verbose)
	opts.NewFlag("D", "debug", &Debug)
	opts.NewFlag("x", "expr: files excluded (.*, tmp.* if none given); tmp always excluded.", &Xcludes)
	Dump = dfltdump
	opts.NewFlag("d", "dir: where to keep the dump, or empty if none", &Dump)
	args, err := opts.Parse(os.Args)
	if err != nil {
		dbg.Warn("%s", err)
		opts.Usage()
		dbg.Exits(err)
	}
	if len(Xcludes) == 0 {
		Xcludes = []string{".*", "tmp.*", "*.tmp"}
	}
	Xcludes = append(Xcludes, "tmp")
	if len(args) == 0 {
		dbg.Warn("arguments missing")
		opts.Usage()
		dbg.Exits("usage")
	}
	if Skip && Once {
		dbg.Fatal("can't skip the current dump and dump once now")
	}
	nt := 0
	ec := make(chan bool)
	for i := 0; i < len(args); i++ {
		al := strings.SplitN(args[i], "!", 2)
		if len(al) == 1 {
			al = append(al, al[0])
			al[0] = path.Base(al[0])
		}
		t, err := lfs.New(al[0], al[1], lfs.RO)
		if err != nil {
			dbg.Warn("%s: %s", al[0], err)
			continue
		}
		t.ReadAttrs(true)
		nt++
		go dump(Dump, t, ec)
	}
	if nt == 0 {
		dbg.Fatal("no trees to dump")
	}
	for nt > 0 {
		<-ec
		nt--
	}
}
Пример #10
0
func Removes(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		for _, dp := range RemovePaths {
			printf("remove %s\n", dp)
			p := zx.Path(d, dp)
			if err := os.Remove(p); err != nil {
				t.Fatalf("rm %s: %s", p, err)
			}
		}
		for _, dp := range BadRemovePaths {
			printf("remove %s\n", dp)
			p := zx.Path(d, dp)
			if err := os.Remove(p); err == nil {
				t.Fatalf("rm %s: did not fail", p)
			}
		}
	}
}
Пример #11
0
func (t *Fs) getdir(f File, d zx.Dir, off, count int64, c chan<- []byte) error {
	gf, ok := f.(Walker)
	if !ok {
		return nil
	}
	ns, err := gf.Getdir()
	if err != nil {
		return err
	}
	sort.Sort(sort.StringSlice(ns))
	if d["name"] == "/" {
		ns = append([]string{"Ctl"}, ns...)
	}
Dloop:	for _, n := range ns {
		if n == "" {
			err = fmt.Errorf("%s: empty name in getdir", d["path"], n)
			app.Warn("fs bug: %s", err)
			return err
		}
		if off > 0 {
			off--
			continue
		}
		switch count {
		case zx.All:
			break
		case 0:
			break Dloop
		default:
			count--
		}
		if d["name"]=="/" && n == "Ctl" {
			cd := ctldir.Dup()
			cd["tpath"] = t.path
			cd.Send(c)
			continue
		}
		cf, err := gf.Walk(n)
		if err != nil {
			return err
		}
		cp := zx.Path(d["path"], n)
		cd, err := t.statf(cf, cp)
		if err != nil {
			return err
		}
		t.Dprintf("getdir %s: %s\n", gf, cf)
		if _, err := cd.Send(c); err != nil {
			return err
		}
	}
	return nil
}
Пример #12
0
func newDumpDir(dir, dfpath string, rf zx.File, ds []zx.Dir, dhash []string) error {
	if len(dhash) != 2*len(ds) {
		panic("newDumpDir: dhash length bug")
	}
	dprintf("create %s\t%s\n", dfpath, rf.D["path"])
	if err := os.MkdirAll(dfpath, 0750); err != nil {
		return err
	}
	var err error
	for i := 0; i < len(ds); i++ {
		cname := dhash[2*i]
		if cname == "" {
			continue // entry had errors
		}
		if cname != ds[i]["name"] {
			panic("newDumpDir: bad entry")
		}
		cdfpath := zx.Path(dir, dhash[2*i+1])
		cpath := zx.Path(dfpath, cname)
		dprintf("link %s\t<- %s\n", cdfpath, cpath)
		var e error
		e = os.Symlink(cdfpath, cpath)
		// TODO: save user attributes from ds[i] for cname at dfpath/.#zx
		if err == nil && e != nil {
			err = e
		}
		if e == nil {
			saveAttrs(dfpath, ds[i])
		}
	}
	mt := rf.D.Time("mtime")
	os.Chtimes(dfpath, mt, mt)
	mode := rf.D.Int("mode")
	if mode != 0 {
		// uncomment to set dir modes -w
		// mode = mode &^ 0222
		os.Chmod(dfpath, os.FileMode(mode))
	}
	return err
}
Пример #13
0
func Gets(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		for _, fp := range GetFPaths {
			p := zx.Path(d, fp)
			dat, err := ioutil.ReadFile(p)
			if err != nil {
				t.Fatalf("get %s: %s", p, err)
			}
			printf("got %d bytes \n\n", len(dat))
			if string(dat) != string(FileData[fp]) {
				printf("got <%s>\nexpected<%s>\n",
					string(dat), string(FileData[fp]))
				t.Fatalf("%s: bad data", p)
			}
		}
		for _, dp := range GetDPaths {
			printf("getall %s\n", dp)
			p := zx.Path(d, dp)
			cs := Children(p)
			printf("children `%s`\n", strings.Join(cs, " "))
			if strings.Join(cs, " ") != GetDOuts[dp] {
				t.Logf("got %s", strings.Join(cs, " "))
				t.Fatalf("bad dir data for %s", dp)
			}
		}
		for _, fp := range BadPaths {
			p := zx.Path(d, fp)
			_, err := ioutil.ReadFile(p)
			if err == nil {
				t.Fatalf("%s did not fail", fp)
			}
		}
	}
}
Пример #14
0
func (t *Lfs) stat(rid string) (zx.Dir, error) {
	rid, err := zx.AbsPath(rid)
	if err != nil {
		return nil, err
	}
	if rid == "/Ctl" {
		d := ctldir.Dup()
		d["tpath"] = t.path
		return d, nil
	}
	path := zx.Path(t.path, rid)
	st, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	nd := 0
	sum := ""
	if st.IsDir() {
		nd, sum = dirsz(path)
		if rid == "/" {
			nd++
		}
	}
	d := zx.NewDir(st, nd)
	if t.readattrs {
		t.fileAttrs(path, d)
	}
	if sum != "" {
		d["Sum"] = sum
	}
	d["tpath"] = t.path
	d["path"] = rid
	d["spath"] = rid
	d["proto"] = "lfs"
	if rid == "/" {
		d["name"] = "/"
	}
	if d["Uid"] == "" {
		d["Uid"] = dbg.Usr
	}
	if d["Gid"] == "" {
		d["Gid"] = dbg.Usr
	}
	if d["Wuid"] == "" {
		d["Wuid"] = dbg.Usr
	}
	return d, nil
}
Пример #15
0
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
}
Пример #16
0
func Stats(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	for _, d := range dirs {
		for _, st := range StatTests {
			p := zx.Path(d, st.Path)
			fi, err := os.Stat(p)
			if err == nil && st.Fails {
				t.Fatalf("%s did not fail", st.Path)
			}
			if err != nil && !st.Fails {
				t.Fatalf("%s did fail", st.Path)
			}
			printf("\t`%s`,\n", stat(fi))
			if !st.Fails && stat(fi) != st.Res {
				t.Fatalf("wrong stat <%s> vs <%s>", stat(fi), st.Res)
			}
		}
	}
}
Пример #17
0
func dumpFile(dir, name string, f zx.File) (string, error) {
	dc := f.T.Get(f.D["path"], 0, zx.All, "")
	h := sha1.New()
	for dat := range dc {
		h.Write(dat)
	}
	err := cerror(dc)
	if err != nil {
		dprintf("dump file %s: get: %s\n", f.D["path"], err)
		return "", err
	}
	sum := h.Sum(nil)
	s := fmt.Sprintf("%02x/%02x/%036x", sum[0], sum[1], sum[2:])
	dfpath := zx.Path(dir, s)
	fi, err := os.Stat(dfpath)
	dprintf("dump file %s\t%s\n", name, s)
	if fi != nil {
		return s, nil
	}
	vprintf("%s: new %s\n", os.Args[0], name)
	return s, newDumpFile(dfpath, f)
}
Пример #18
0
// Resolve a name and return the prefix path, the array of mount points for it and the server paths
// for each mount point.
// The path must be absolute.
func (ns *Tree) Resolve(name string) (pref string, mnts []zx.Dir, spaths []string, err error) {
	path, err := zx.AbsPath(name)
	if err != nil {
		return "", nil, nil, err
	}
	ns.dprintf("resolve %s\n", path)
	ns.lk.RLock()
	defer ns.lk.RUnlock()
	var p *prefix
	for _, np := range ns.pref {
		if zx.HasPrefix(path, np.name) {
			ns.dprintf("\thasprefix %s %s\n", path, np.name)
			p = np
		}
	}
	if p == nil {
		ns.dprintf("\tno prefixes\n")
		return "", nil, nil, dbg.ErrNotExist
	}
	suff := zx.Suffix(path, p.name)
	mnts = make([]zx.Dir, 0, len(p.mnt))
	spaths = []string{}
	for _, d := range p.mnt {
		if isfinder(d) || suff=="" || suff=="/" {
			mnts = append(mnts, d.Dup())
			spath := zx.Path(suff, d["spath"])
			spaths = append(spaths, spath)
			ns.dprintf("\ts='%s' d=%s\n", spath, d)
		} else {
			ns.dprintf("\tskip %s\n", d)
		}
	}
	if len(mnts) == 0 {
		ns.dprintf("\tno prefixes left\n")
		return "", nil, nil, dbg.ErrNotExist
	}
	return p.name, mnts, spaths, nil
}
Пример #19
0
// Make sure /foo behaves as a file issuing calls from 3 fds.
func AsAFile(t Fataler, dirs ...string) {
	if len(dirs) == 0 {
		t.Fatalf("not enough dirs")
	}
	fn := "/foo"
	for _, d := range dirs {
		p := zx.Path(d, fn)
		fd, err := os.Create(p)
		if err != nil {
			t.Fatalf("create: %s: %s", d, err)
		}
		fd1, err := os.Create(p)
		if err != nil {
			t.Fatalf("create: %s: %s", d, err)
		}
		fd2, err := os.Create(p)
		if err != nil {
			t.Fatalf("create: %s: %s", d, err)
		}
		fds := []rwtest.Object{fd, fd1, fd2}
		rwtest.AsAConcFile(t, fds, 1000, 128 * 1024, 3803)
	}
}
Пример #20
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)
	}
}
Пример #21
0
// 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
}
Пример #22
0
// 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)
	}
	
}
Пример #23
0
func (t *Fs) Move(from, to string) chan error {
	t.dprintf("move %s %s \n", from, to)
	cs := t.IOstats.NewCall(zx.Smove)
	c := make(chan error, 1)
	from, ferr := zx.AbsPath(from)
	to, terr := zx.AbsPath(to)
	var pfrom, pto *mFile
	var leftto []string
	var err error
	var fd, pd *mFile
	if ferr != nil {
		err = ferr
	} else if terr != nil {
		err = terr
	} else if from == to {
		c <- nil
		close(c)
		cs.End(false)
		return c
	}
	if err == nil {
		fd, _, err = t.walk(path.Dir(from), nil)
	}
	if err == nil && !t.noPerms() {
		fd.mlk.Lock()
		if !fd.d.CanWrite(t.ai) {
			err = fmt.Errorf("%s: %s", fd, dbg.ErrPerm)
		}
		fd.mlk.Unlock()
	}
	if err == nil {
		pd, _, err = t.walk(path.Dir(to), nil)
	}
	var pdpath, pdspath string
	if err == nil {
		pd.mlk.Lock()
		if !t.noPerms() && !pd.d.CanWrite(t.ai) {
			err = fmt.Errorf("%s: %s", pd, dbg.ErrPerm)
		}
		pdpath = pd.d["path"]
		pdspath = pd.d["spath"]
		pd.mlk.Unlock()
	}
	if err != nil {
		goto Fail
	}

	if from=="/Ctl" || to=="/Ctl" || from == "/" || to == "/" {
		err = dbg.ErrPerm
	} else if pfrom, _, ferr = t.walk(from, nil); ferr != nil {
		err = ferr
	} else if inconsistent(from, to) {
		err = errors.New("inconsistent move")
	} else if pto, leftto, terr = t.walk(to, nil); terr != nil && !dbg.IsNotExist(terr) {
		err = terr
	} else if len(leftto) > 1 {
		err = terr
	} else if len(leftto) == 0 && pto.d["type"] == "d" {
		err = fmt.Errorf("%s: %s", pto, dbg.ErrExists)
	} else if len(leftto) == 0 && pto.d["type"] != pfrom.d["type"] { // race: no lock in types
		err = fmt.Errorf("%s: incosistent move", pfrom)
	}
Fail:	if err != nil {
		c <- err
		t.dprintf("move %s: %s\n", from, err)
		close(c, err)
		cs.End(true)
		return c
	}
	t.detach(pfrom)
	pfrom.mlk.Lock()
	pfrom.name= path.Base(to)
	pfrom.d["name"] = pfrom.name
	pfrom.d["path"] = zx.Path(pdpath, pfrom.name)
	pfrom.d["spath"] = zx.Path(pdspath, pfrom.name)
	pfrom.mlk.Unlock()
	pfrom.moved()
	pd.mlk.Lock()
	pd.clk.Lock()
	pd.attach(pfrom)
	pd.clk.Unlock()
	pd.mlk.Unlock()
	t.dprintf("move %s: ok\n", from)
	close(c)
	cs.End(false)
	return c
}
Пример #24
0
// Perform black box testing of dir1
// by performing random FS ops in it and a read OS dir and comparing the trees
// and the results from the operations.
// There can be at most one invocation of this function at a time.
func AsAFs(t Fataler, dirs ...string) {
	dir1 := dirs[0]
	os.RemoveAll(osdir)
	defer os.RemoveAll(osdir)
	if err := os.Mkdir(osdir, 0775); err != nil {
		t.Fatalf("mkdir: %s", err)
	}
	dir1 = dir1 + "/fst"
	os.RemoveAll(dir1)
	if err := os.Mkdir(dir1, 0775); err != nil {
		t.Fatalf("mkdir: %s", err)
	}
	defer os.RemoveAll(dir1)

	opc := make(chan fsOp)
	nops := 0
	for o := oFirst; o < oRead; o++ {
		n := nOps
		if o == oCreate || o == oMkdir {
			n += nOps
		}
		nops += n
		go func(o fsOp, n int) {
			for i := 0; i < n; i++ {
				if ok := opc <- o; !ok {
					break
				}
			}
		}(o, n)
	}
	for o := oRead; o < oMax; o++ {
		go func(o fsOp) {
			nops += nOps
			for i := 0; i < nOps; i++ {
				if ok := opc <- o; !ok {
					break
				}
			}
		}(o)
	}
	t.Logf("%d ops", nops)
	counts = map[fsOp]int{}
	for i := 0; i < nops; i++ {
		// Make an update operation
		op := <- opc
		if op == oRemove && i %2 == 0 {
			continue
		}
		fp := paths[i%len(paths)]
		p1 := zx.Path(dir1, fp)
		p2 := zx.Path(osdir, fp)
		ok := calls[op](t, p1, p2)
		if ok {
			counts[op] = counts[op] + 1
		}
	}
	for o := oFirst; o < oMax; o++ {
		t.Logf("op %v: %d ok", o, counts[o])
	}
	close(opc)
}
Пример #25
0
func (f *File) files(rc chan<- *File)  error {
	if ok := rc <- f; !ok {
		return cerror(rc)
	}
	for _, c := range f.Child {
		if err := c.files(rc); err != nil {
			return err
		}
	}
	return nil
}


// Enumerate all files in db
func (db *DB) Files() <-chan *File {
	rc := make(chan *File)
	if db == nil || db.Root == nil {
		close(rc)
	} else {
		go func() {
			close(rc, db.Root.files(rc))
		}()
	}
	return rc
}

// Debug dump
func (db *DB) DumpTo(w io.Writer) {
	fmt.Fprintf(w, "%s\n", db)
	if db == nil {
		return
	}
	fc := db.Files()
	for f := range fc {
		fmt.Fprintf(w, "%s\n", f)
	}
}

// Walk to the given path
func (db *DB) Walk(elems ...string) (*File, error) {
	f := db.Root
	for _, e := range elems {
		cf, err := f.Walk1(e)
		if err != nil {
			return nil, err
		}
		f = cf
	}
	return f, nil
}

type byName []*File

func (b byName) Len() int { return len(b) }
func (b byName) Less(i, j int) bool { return b[i].D["name"] < b[j].D["name"] }
func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }

// add or update the entry for a  dir into db.
func (db *DB) Add(d zx.Dir) error {
	f := &File{
		D: d,
	}
	elems := zx.Elems(d["path"])
	if len(elems) == 0 {
		db.Root = f
		return nil
	}
	parent := elems[0 : len(elems)-1]
	name := elems[len(elems)-1]
	pdir := zx.Path(parent...)
	if pdir != db.lastpdir || db.lastpf == nil {
		pf, err := db.Walk(parent...)
		if err != nil {
			dprintf("add: can't walk: %s\n", err)
			return err
		}
		db.lastpdir = pdir
		db.lastpf = pf
	}
	vprintf("add %s to %s\n", name, db.lastpf)
	child := db.lastpf.Child
	for _, cf := range child {
		if cf.D["name"] == name {
			cf.D = d
			if cf.D["type"] != "d" {
				cf.Child = nil
			}
			return nil
		}
	}
	
	child = append(child, f)
	if n := len(child); n > 1 && child[n-1].D["name"] < child[n-2].D["name"] {
		sort.Sort(byName(child))
	}
	db.lastpf.Child = child
	return nil
}

// part of zx.Finder
type Finder interface {
	Find(path, pred string, spref, dpref string, depth0 int) <-chan zx.Dir
}

// Scan the underlying tree and re-build the metadata db.
// Dials the tree if necessary.
// Only the first error is reported.
func (db *DB) scan(fs Finder) error {
	dprintf("scan /,%s\n", db.Pred)
	dc := fs.Find("/", db.Pred, "", "", 0)
	db.lastpdir = ""
	db.lastpf = nil
	db.Root = nil
	var err error
	for d := range dc {
		if d["path"] == "/Ctl" || d["path"] == "/Chg" {
			continue
		}
		vprintf("add %s\n", d)
		if e := db.Add(d); err == nil && e != nil {
			err = nil
		}
	}
	if err != nil {
		return err
	}
	return cerror(dc)	
}

// Send the db through c.
// The channel must preserve message boundaries and is not closed by this function. 
// The db name is first sent and then one packed dir per file recorded in the db.
// An empty msg is sent to signal the end of the stream of dir entries
func (db *DB) SendTo(c chan<- []byte) error {
	if ok := c <- []byte(db.Name); !ok {
		return cerror(c)
	}
	if ok := c <- []byte(db.Pred); !ok {
		return cerror(c)
	}
	fc := db.Files()
	var err error
	for f := range fc {
		if f == nil || f.D == nil {
			err = errors.New("nil file sent")
			break
		}
		if _, err = f.D.Send(c); err != nil {
			break
		}
	}
	if err != nil {
		close(fc, err)
	} else {
		err = cerror(fc)
	}
	c <- []byte{}
	return err
}

// Receive a db from c assuming it was sent in the same format used by SendTo.
func RecvDBFrom(c <-chan []byte) (*DB, error) {
	nm, ok1 := <-c
	pred, ok2 := <-c
	if !ok1 || !ok2 {
		return nil, cerror(c)
	}
	db := &DB{
		Name: string(nm),
		Pred: string(pred),
	}
	db.lastpdir = ""
	db.lastpf = nil
	db.Root = nil
	for {
		d, err := zx.RecvDir(c)
		if err != nil || len(d) == 0 {
			return db, err
		}
		if d["path"] == "/Ctl" || d["path"] == "/Chg" {
			continue
		}
		dprintf("add %s\n", d)
		if err := db.Add(d); err != nil {
			return db, err
		}
	}
}

// Save a db to a local file
func (db *DB) Save(fname string) error {
	tname := fname + "~"
	fd, err := os.Create(tname)
	if err != nil {
		return err
	}
	dc := make(chan []byte)
	go func() {
		close(dc, db.SendTo(dc))
	}()
	_, _, err = nchan.WriteMsgsTo(fd, dc)
	fd.Close()
	close(dc, err)
	if err != nil {
		return err
	}
	return os.Rename(tname, fname)
}

func LoadDB(fname string) (*DB, error) {
	fd, err := os.Open(fname)
	if err != nil {
		return nil, err
	}
	dc := make(chan []byte)
	go func() {
		_, _, err := nchan.ReadMsgsFrom(fd, dc)
		close(dc, err)
	}()
	db, err := RecvDBFrom(dc)
	close(dc, err)
	return db, err
}
Пример #26
0
func find(dump, dpref, rel string, dc chan<- zx.Dir, ufile zx.Dir) {
	droot := fpath.Join(dump, dpref)
	years, err := cmd.GetDir(droot)
	if err != nil {
		cmd.Warn("%s", err)
		return
	}
	for i := len(years) - 1; i >= 0; i-- {
		year := years[i]["name"]
		if ignored(year, "") {
			continue
		}
		ypath := years[i]["path"]
		days, err := cmd.GetDir(ypath)
		if err != nil {
			cmd.Warn("%s: %s", ypath, err)
			continue
		}
		lastsz, lastmt, lastm := "", "", ""
		for j := len(days) - 1; j >= 0; j-- {
			day := days[j]["name"]
			if ignored(year, day) {
				continue
			}
			fpath := fpath.Join(days[j]["path"], rel)
			d, err := cmd.Stat(fpath)
			if err != nil {
				if !force {
					cmd.Dprintf("find: %s", err)
					return
				}
				continue
			}
			newm, newsz, newmt := d["mode"], d["size"], d["mtime"]
			if newsz == lastsz && newmt == lastmt && newm == lastm {
				continue
			}
			lastm, lastsz, lastmt = newm, newsz, newmt
			d["upath"] = ufile["path"]
			d["uupath"] = ufile["upath"]
			if ok := dc <- d; !ok {
				return
			}
			if !all {
				return
			}
		}
	}
}

func report(dc chan zx.Dir, donec chan bool) {
	last := ""
	for d := range dc {
		if last == "" {
			last = d["Upath"]
			if last == "" {
				last = d["path"]
			}
		}
		p := d["path"]
		cmd.Dprintf("found '%s'\n", p)
		var err error
		switch {
		case xcmd != "":
			_, err = cmd.Printf("%s %s %s\n", xcmd, p, last)
		case dflag:
			dcmd := fmt.Sprintf(`9 diff -n %s %s`, p, last)
			_, err = cmd.Printf("%s\n", dcmd)
			if err != nil {
				cmd.Warn("diff: %s", err)
				continue
			}
		case lflag:
			_, err = cmd.Printf("%s\n", d.Fmt())
		case cflag:
			_, err = cmd.Printf("cp %s %s\n", p, d["Upath"])
		default:
			_, err = cmd.Printf("%s\n", d["path"])
		}
		if err != nil {
			close(dc, err)
		}
		last = p
	}
	close(donec, cerror(dc))
}

func hist(in <-chan face{}) error {
	dc := make(chan zx.Dir)
	ec := make(chan bool)
	go report(dc, ec)
	var sts error
	for m := range in {
		switch m := m.(type) {
		case zx.Dir:
			cmd.Dprintf("got %T %s\n", m, m["path"])
			file := m["path"]
			if m["upath"] == "" {
				m["upath"] = m["path"]
			}
			ddir := dump
			dpref := ""
			rel := ""
			switch {
			case zx.HasPrefix(file, "/zx"):
				if ddir == "" {
					ddir = "/dump"
				}
				dpref = "/zx"
				rel = zx.Suffix(file, "/zx")
			case zx.HasPrefix(file, "/u/gosrc/src/clive"):
				if ddir == "" {
					ddir = "/u/dump"
				}
				dpref = "clive"
				rel = zx.Suffix(file, "/u/gosrc/src/clive")
			case zx.HasPrefix(file, "/u"):
				if ddir == "" {
					ddir = "/u/dump"
				}
				els := zx.Elems(file)
				if len(els) < 3 {
					cmd.Warn("%s: too few path elements", m["upath"])
					sts = errNoDump
					continue
				}
				dpref = els[1]
				rel = zx.Path(els[2:]...)
			default:
				cmd.Warn("%s: %s", m["upath"], errNoDump)
				sts = errNoDump
				continue
			}
			find(ddir, dpref, rel, dc, m.Dup())
		default:
			cmd.Dprintf("got %T\n", m)

		}
	}
	close(dc, cerror(in))
	<-ec
	if sts == nil {
		sts = cerror(ec)
	}
	if sts == nil {
		sts = cerror(in)
	}
	return sts
}

// Run cnt in the current app context.
func main() {
	c := cmd.AppCtx()
	cmd.UnixIO("err")
	opts.NewFlag("D", "debug", &c.Debug)
	opts.NewFlag("f", "force search past file removals", &force)
	opts.NewFlag("l", "produce a long listing (or print just the name)", &lflag)
	opts.NewFlag("c", "copy the file from the dump", &cflag)
	opts.NewFlag("d", "print file differences", &dflag)
	opts.NewFlag("x", "cmd: print lines to execute this command between versions", &xcmd)
	opts.NewFlag("a", "list all copies that differ, not just the last one.", &all)
	opts.NewFlag("p", "dumpdir: path to dump (default is /dump or /u/dump)", &dump)
	t := time.Now()
	when := t
	opts.NewFlag("w", "date: backward search start time (default is now)", &when)
	ux := false
	opts.NewFlag("u", "unix IO", &ux)
	args := opts.Parse()
	if (all && cflag) || (force && !all) {
		cmd.Warn("incompatible flags")
		opts.Usage()
	}
	if ux {
		cmd.UnixIO("out")
	}
	lastyear = ""
	lastday = ""
	if !t.Equal(when) {
		y := when.Year()
		m := when.Month()
		d := when.Day()
		if y == 0 {
			y = t.Year()
		}
		lastyear = fmt.Sprintf("%04d", y)
		lastday = fmt.Sprintf("%02d%02d", m, d)
	}
	if len(args) != 0 {
		cmd.SetIn("in", cmd.Dirs(args...))
	}
	in := cmd.In("in")
	if err := hist(in); err != nil {
		cmd.Fatal(err)
	}
}
Пример #27
0
func dumpDir(dir, name string, rf zx.File) (string, error) {
	dprintf("dump dir %s %s %s\n", dir, name, rf.D["path"])
	ds := []zx.Dir{}
	istmp := rf.D["name"] == "tmp"
	if !istmp {
		var err error
		ds, err = zx.GetDir(rf.T, rf.D["path"])
		if err != nil {
			dbg.Warn("dumpdir: %s: %s", rf.D["path"], err)
			return "", err
		}
	} else {
		vprintf("%s: temp %s\n", os.Args[0], name)
	}
	dhash := []string{}
	nds := []zx.Dir{}
	for _, d := range ds {
		if d["name"] == "" {
			dbg.Warn("dumpdir: %s: no name", rf.D["path"])
		}
		if d["name"] == "NODUMP" {
			nds = []zx.Dir{}
			dbg.Warn("dumpdir: %s: no dump", rf.D["path"])
			break
		}
		if d["name"] == "FROZEN" {
			vprintf("%s: XXX frozen %s\n", os.Args[0], name)
			/* dir is frozen and the FROZEN contains
			 * the dump path for dir.
			 */
			data, err := zx.GetAll(rf.T, d["path"])
			if err != nil {
				return "", err
			}
			s := string(data)
			if len(strings.Split(s, "/")) != 3 {
				return "", fmt.Errorf("wrong contents in %s", d["path"])
			}
			vprintf("%s: frozen %s\n", os.Args[0], name)
			return strings.TrimSpace(s), nil
		}
		if excluded(d["name"]) {
			dprintf("dump ignored %s\n", d["path"])
			continue
		}
		if t := d["type"]; t != "d" && t != "-" {
			dbg.Warn("dump ignored %s type '%s'\n", d["path"], t)
			continue
		}
		nds = append(nds, d)
	}
	ds = nds
	for _, d := range ds {
		dspath := zx.Path(name, d["name"])
		df, err := zx.Walk(rf.T, rf.D, d["name"])
		if dspath == name {
			panic("zx dump bug")
		}
		if err != nil {
			dbg.Warn("walk: %s: %s", df["path"], err)
			dhash = append(dhash, "")
			dhash = append(dhash, "")
			continue
		}
		var s string
		var e error
		switch d["type"] {
		case "d":
			s, e = dumpDir(dir, dspath, zx.File{rf.T, df})
		case "-":
			s, e = dumpFile(dir, dspath, zx.File{rf.T, df})
		default:
			panic("dump dir type bug")
		}
		if e == nil {
			dhash = append(dhash, d["name"])
			dhash = append(dhash, s)
		} else {
			dbg.Warn("%s: %s", df["path"], e)
		}
		if err == nil && e != nil {
			err = e
			dhash = append(dhash, "")
			dhash = append(dhash, "")
		}
	}
	dval := strings.Join(dhash, "\n")
	h := sha1.New()
	h.Write([]byte(dval))
	sum := h.Sum(nil)
	s := fmt.Sprintf("%02x/%02x/%036x", sum[0], sum[1], sum[2:])
	dprintf("dump dir %s %s\n", name, s)
	dfpath := zx.Path(dir, s)
	fi, _ := os.Stat(dfpath)
	if fi != nil {
		return s, nil
	}
	vprintf("%s: new %s\n", os.Args[0], name)
	return s, newDumpDir(dir, dfpath, rf, ds, dhash)
}
Пример #28
0
func (t *Lfs) get(rid string, off, count int64, dc chan<- []byte, cs *zx.CallStat) (int64, error) {
	rid, err := zx.AbsPath(rid)
	if err != nil {
		return 0, err
	}
	if rid == "/Ctl" {
		return t.getCtl(off, count, dc, cs)
	}
	path := zx.Path(t.path, rid)
	fd, err := os.Open(path)
	if err==nil && t.ai!=nil && !t.NoPermCheck {
		_, _, err = t.canWalkTo(rid, 0444)
	}
	if err != nil {
		return 0, err
	}
	defer fd.Close()
	st, err := fd.Stat()
	if err != nil {
		return 0, err
	}
	if off!=0 && !st.IsDir() {
		if _, err := fd.Seek(off, 0); err != nil {
			return 0, err
		}
	}
	if st.IsDir() {
		ds, err := ioutil.ReadDir(path)
		nd := 0
		tot := 0
		ctlsent := false
		var xds map[string]zx.Dir
		if t.readattrs {
			xds, _ = t.dirAttrs(path)
		}
	Dloop:
		for i := 0; i < len(ds); {
			if off > 0 {
				off--
				if !ctlsent && rid=="/" {
					ctlsent = true
				} else {
					i++
				}
				continue
			}
			switch count {
			case zx.All:
				break
			case 0:
				break Dloop
			default:
				count--
			}
			if !ctlsent && rid=="/" {
				ctlsent = true
				nd++
				d := ctldir
				n, _ := d.Send(dc)
				nd++ // but not i++
				tot += n
				continue
			}
			fi := ds[i]
			if fi.Name() == afname {
				if i == len(ds)-1 {
					break
				}
				ds = append(ds[:i], ds[i+1:]...)
				fi = ds[i]
			}
			cpath := zx.Path(path, fi.Name())
			n := 0
			sum := ""
			if fi.IsDir() {
				n, sum = dirsz(cpath)
			}
			d := zx.NewDir(fi, n)
			d["path"] = zx.Path(rid, fi.Name())
			d["spath"] = d["path"]
			d["tpath"] = t.path
			if t.readattrs {
				if xd, ok := xds[fi.Name()]; ok {
					for k, v := range xd {
						if zx.IsUpper(k) {
							d[k] = v
						}
					}
				} else {
					d["Uid"] = dbg.Usr
					d["Gid"] = dbg.Usr
				}
			}
			if sum != "" {
				d["Sum"] = sum
			}
			cs.Send(0)
			n, err := d.Send(dc)
			if err != nil {
				return int64(tot), err
			}
			nd++
			i++
			tot += n
		}
		return int64(tot), err
	}
	if count == zx.All {
		cs.Sending()
		nm, n, err := nchan.ReadBytesFrom(fd, dc)
		cs.Sends(nm, n)
		return n, err
	}
	rr := io.LimitReader(fd, count)
	cs.Sending()
	nm, n, err := nchan.ReadBytesFrom(rr, dc)
	cs.Sends(nm, n)
	return n, err
}