// no locks, used only at init time func (t *Fs) reloadChild(f *mFile) { ds, err := zx.GetDir(t.lfs, f.d["path"]) if err != nil { dbg.Warn("%s: reload: %s", t.name, err) return } for _, d := range ds { if d["path"] == "/Ctl" || d["path" ] == "/Chg" { continue } cf := &mFile{ name: d["name"], d: zx.Dir{ "name": d["name"], "path": d["path"], "spath": d["path"], "tpath": t.path, "type": d["type"], "Wuid": d["Wuid"], "Sum": d["Sum"], }, } for k, v := range d.UsrAttrs() { cf.d[k] = v } f.child = append(f.child, cf) if cf.d["type"] == "d" { t.reloadChild(cf) } } }
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) } } }
/* 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 }
func GetDir(path string) ([]zx.Dir, error) { if len(path) > 0 && path[0] == '#' { return nil, fmt.Errorf("%s: %s", path, dbg.ErrPerm) } path = app.AbsPath(path) _, trs, spaths, err := app.ResolveTree(path) if err != nil { return nil, err } return zx.GetDir(trs[0], spaths[0]) }
// read (or re-read) dir data and update children stats. // The hash attribute of the file is updated with the sha1 for the data, // but it's not written to the underlying file. /// zd is locked by caller. func (zd *Dir) getDir() error { zd.zprintf("Lget", "readdir") ds, err := zx.GetDir(zd.z.fs, zd.path) if err != nil { zd.dprintf("get", err) return err } names := []string{} nchild := make(map[string]*Dir, len(ds)) firstread := zd.child == nil for i := 0; i < len(ds); i++ { cd := ds[i] cname := cd["name"] if cname=="" || cname=="." || cname==".." || cname==".#zx" { continue } zcd, ok := zd.child[cname] if ok && !zcd.ghost { zcd.Lock() // and must post an update only if zcd changes mchg, dchg, _ := zcd.stated("getdir", cd, nil) if mchg || dchg { zd.z.changed(zcd) } zcd.Unlock() delete(zd.child, cname) } else { zcd = zd.z.newDir(cd) zcd.parent = zd zcd.refreshMeta() if !firstread { zcd.RLock() zd.z.changed(zcd) zcd.RUnlock() } } if !zcd.ghost { nchild[cname] = zcd names = append(names, cname) } } for _, zcd := range zd.child { zcd.Lock() zcd.kill("readdir") zd.z.changed(zcd) zcd.Unlock() } zd.child = nchild osum := zd.d["Sum"] sort.Sort(sort.StringSlice(names)) h := sha1.New() for _, n := range names { h.Write([]byte(n)) } sum := h.Sum(nil) zd.d["Sum"] = fmt.Sprintf("%040x", sum) zd.refreshData() if osum != zd.d["Sum"] { zd.wstatAttrs("Sum") } return nil }
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) }
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) } }
// Check that perms are actually checked in old files and dirs func RWXPerms(t Fataler, fss ...zx.Tree) { if len(fss) == 0 { t.Fatalf("no fs given") } fs := authfs(t, fss[0].(zx.RWTree)) if <-fs.Mkdir("/chkd", zx.Dir{"mode": "0777", "Gid": "gid1"}) != nil { t.Fatalf("couldn't mkdir /chkd gid") } if <-fs.Mkdir("/chkd/o", zx.Dir{"mode": "0777", "Gid": "gid1"}) != nil { t.Fatalf("couldn't mkdir /chkd gid") } // Check out dirs rfn := func(fs zx.RWTree) error { _, err := zx.GetDir(fs, "/chkd") return err } out := ugo(t, fs, "/chkd", 4, rfn) printf("dir rd ugo: %s\n", out) if out != "yyyyynynnnnn" { t.Fatalf("dir read perms are %s", out) } wfn := func(fs zx.RWTree) error { err := <-fs.Mkdir("/chkd/x", zx.Dir{"mode": "0777"}) if err != nil { return err } return <-fs.Remove("/chkd/x") } out = ugo(t, fs, "/chkd", 2, wfn) printf("dir wr ugo: %s\n", out) if out != "yyyyynynnnnn" { t.Fatalf("dir write perms are %s", out) } xfn := func(fs zx.RWTree) error { _, err := zx.GetDir(fs, "/chkd/o") return err } out = ugo(t, fs, "/chkd", 1, xfn) printf("dir ex ugo: %s\n", out) if out != "yyyyynynnnnn" { t.Fatalf("dir exec perms are %s", out) } // Check out files if err := zx.PutAll(fs, "/chkf", zx.Dir{"mode": "0777"}, []byte("hi")); err != nil { t.Fatalf("put: %s", err) } if err := <-fs.Wstat("/chkf", zx.Dir{"Gid": "gid1"}); err != nil { t.Fatalf("wstat: %s", err) } rfn = func(fs zx.RWTree) error { _, err := zx.GetAll(fs, "/chkf") return err } out = ugo(t, fs, "/chkf", 4, rfn) printf("file rd ugo: %s\n", out) if out != "yyyyynynnnnn" { t.Fatalf("file read perms are %s", out) } wfn = func(fs zx.RWTree) error { return zx.PutAll(fs, "/chkf", nil, []byte("there")) } out = ugo(t, fs, "/chkf", 2, wfn) printf("file wr ugo: %s\n", out) if out != "yyyyynynnnnn" { t.Fatalf("file write perms are %s", out) } // We can't check out exec perms, because the underlying OS has // its own idea of who can exec the file. // see who can change modes. m := 0 wfn = func(fs zx.RWTree) error { m++ return <-fs.Wstat("/chkf", zx.Dir{"mode": fmt.Sprintf("0%o", m)}) } out = ugo(t, fs, "/chkf", 2, wfn) printf("file wstat ugo: %s\n", out) if out != "ynnynnynnynn" { t.Fatalf("file wstat perms are %s", out) } }