// 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) } }
func (c *FileInfo) syncDel() { if c.path == "" || c.path == "/" { panic("sync: DEL /") return } // There's a potential problem if a file was created remotelly // since we removed a subtree locally, but it's a race anyway. err := <- c.rfs.RemoveAll(c.path) if err != nil && !dbg.IsNotExist(err) { c.dprintf("%s: sync del: %s\n", c.path, err) c.state = CUnread } c.wasdel = false }
func (t *Fs) put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) error { 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.(Walker) if !ok { return fmt.Errorf("%s: %s", pd["path"], dbg.ErrPerm) } f, err := wpf.Walk(path.Base(rid)) if err != nil && !dbg.IsNotExist(err) { return err } if err != nil { if err := t.matchDir(rid, nil, pred); err != nil { return err } if !t.NoPermCheck && !pd.CanWrite(t.ai) { return fmt.Errorf("%s: %s", rid, dbg.ErrPerm) } if putf, ok := pf.(Putter); ok { return putf.Put(path.Base(rid), d, off, dc) } return fmt.Errorf("%s: %s", pd["path"], dbg.ErrPerm) } else { d, err := f.Stat() if err != nil { return err } if d["type"] == "d" { return fmt.Errorf("%s: %s", rid, dbg.ErrIsDir) } if err := t.matchDir(rid, d, pred); err != nil { return err } if !t.NoPermCheck && !d.CanWrite(t.ai) { return fmt.Errorf("%s: %s", rid, dbg.ErrPerm) } if putf, ok := f.(Putter); ok { return putf.Put("", d, off, dc) } return fmt.Errorf("%s: %s", d["path"], dbg.ErrPerm) } }
func (t *Fs) match(d zx.Dir, err error, rid, fpred string) error { if fpred == "" { return nil } if err != nil { if dbg.IsNotExist(err) { d = zx.Dir{ "path": rid, "name": path.Base(rid), "type": "-", } return t.matchDir(rid, d, fpred) } return err } return t.matchDir(rid, d, fpred) }
func (t *Lfs) match(rid string, fpred string) error { if fpred == "" { return nil } d, err := t.stat(rid) if err != nil { if dbg.IsNotExist(err) { d := zx.Dir{ "path": rid, "name": path.Base(rid), "type": "-", } return t.matchDir(d, fpred) } return err } return t.matchDir(d, fpred) }
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 }
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 }