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