// 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 }
// 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 }
// 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 }