func (t *Fs) get(rid string, off, count int64, dc chan<- []byte, cs *zx.CallStat) error { rid, err := zx.AbsPath(rid) if err != nil { return err } if rid == "/Ctl" { return t.getCtl(off, count, dc, cs) } f, _, err := t.walk(rid, nil) if err == nil && !t.NoPermCheck { f.mlk.Lock() if !f.d.CanRead(t.ai) { err = dbg.ErrPerm } f.mlk.Unlock() } if err != nil { return err } f.mlk.Lock() if f.d["type"] == "d" { f.mlk.Unlock() return f.getDir(off, count, dc, cs) } f.mlk.Unlock() cs.Sending() n, nm, err := f.data.SendTo(off, count, dc) cs.Sends(int64(nm), n) return err }
// locks/unlocks f's data func (f *mFile) getDir(off, count int64, dc chan<- []byte, cs *zx.CallStat) error { f.clk.Lock() ds := make([]*mFile, len(f.child)) copy(ds, f.child) f.clk.Unlock() nd := 0 ctlsent := false Dloop: for i := 0; i < len(ds); { if off > 0 { off-- if !ctlsent && f.name =="/" { ctlsent = true } else { i++ } continue } switch count { case zx.All: break case 0: break Dloop default: count-- } if !ctlsent && f.name=="/" { ctlsent = true nd++ d := ctldir.Dup() d["tpath"] = f.d["tpath"] d.Send(dc) nd++ // but not i++ continue } ds[i].mlk.Lock() d := ds[i].d.Dup() ds[i].mlk.Unlock() cs.Send(0) if _, err := d.Send(dc); err != nil { return err } nd++ i++ } return nil }
func (t *Fs) getCtl(off, count int64, dc chan<- []byte, cs *zx.CallStat) error { var buf bytes.Buffer fmt.Fprintf(&buf, "%s:\n", t.Name()) fmt.Fprintf(&buf, "%s", t.Flags) t.IOstats.Averages() fmt.Fprintf(&buf, "%s\n", t.IOstats.String()) resp := buf.Bytes() o := int(off) if o >= len(resp) { o = len(resp) } resp = resp[o:] n := int(count) if n>len(resp) || n<0 { n = len(resp) } resp = resp[:n] cs.Send(int64(len(resp))) dc <- resp return nil }
func (fs *Cfs) getCtl(off, count int64, pred string, c chan<- []byte, cs *zx.CallStat) (int, error) { var buf bytes.Buffer fmt.Fprintf(&buf, "%s:\n", fs.Name()) users := fs.Users() for _, k := range users { fmt.Fprintf(&buf, "user\t%s\n", k) } fmt.Fprintf(&buf, "%s", fs.Flags) fs.IOstats.Averages() fmt.Fprintf(&buf, "%s\n", fs.IOstats.String()) lctl, _ := zx.GetAll(fs.lfs, "/Ctl") if len(lctl) > 0 { buf.Write(lctl) } rctl, _ := zx.GetAll(fs.rfs, "/Ctl") if len(rctl) > 0 { buf.Write(rctl) } resp := buf.Bytes() o := int(off) if o >= len(resp) { o = len(resp) } resp = resp[o:] n := int(count) if n > len(resp) || n < 0 { n = len(resp) } resp = resp[:n] cs.Send(int64(len(resp))) c <- resp return n, nil }
func (t *Fs) remove(rid string, all bool, cs *zx.CallStat) chan error { c := make(chan error, 1) rid, err := zx.AbsPath(rid) if rid=="/Ctl" || rid == "/" { t.dprintf("remove %s: %s\n", rid, dbg.ErrPerm) err := fmt.Errorf("%s: %s", rid, dbg.ErrPerm) c <- err close(c, err) cs.End(true) return c } f, _, err := t.walk(rid, nil) if f != nil { f.mlk.Lock() } if err == nil && !all && f.d["type"] == "d" && len(f.child) > 0 { err = errors.New("directory is not empty") } if err == nil && !t.noPerms() && !f.d.CanWrite(t.ai) { err = dbg.ErrPerm } if f != nil { if err == nil { f.d["rm"] = "y" } f.mlk.Unlock() } if err != nil { t.dprintf("remove %s: %s\n", rid, err) c <- err close(c, err) cs.End(true) return c } t.detach(f) t.dprintf("remove %s: ok\n", rid) close(c) cs.End(false) return c }
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 }
func (t *Rfs) getrpc(rid string, msg *Msg) <-chan []byte { t.c.Debug = t.Dbg && VerbDebug c := make(chan []byte, 10) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sget, len(raw)) reqc <- raw close(reqc) some := false for rep := range repc { cs.Send(int64(len(rep))) if ok := c <- rep; !ok { close(repc, cerror(c)) break } some = true t.dprintf("get %s: ok\n", rid) } if !some { c <- nil } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("get %s: %s\n", rid, err) } else { t.dprintf("get %s: ok\n", rid) } close(c, err) }() return c } func (t *Rfs) Get(rid string, off, count int64, pred string) <-chan []byte { t.dprintf("get %s %d %d %q\n", rid, off, count, pred) msg := &Msg{Op: Tget, Rid: rid, Off: off, Count: count, Pred: pred} return t.getrpc(rid, msg) } func (t *Rfs) putrpc(rid string, msg *Msg, dc <-chan []byte) chan zx.Dir { t.c.Debug = t.Dbg && VerbDebug c := make(chan zx.Dir, 1) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sput, len(raw)) reqc <- raw nm := 0 tot := 0 for m := range dc { nm++ cs.Recv(int64(len(m))) if ok := reqc <- m; !ok { err := cerror(reqc) close(dc, err) close(c, err) cs.End(err != nil) return } if len(m) == 0 { break } tot += len(m) } close(reqc, cerror(dc)) rep := <-repc var err error var d zx.Dir if len(rep) == 0 { err = cerror(repc) } else { d, _, err = zx.UnpackDir(rep) if err==nil && d==nil { err = errors.New("null dir in put reply") } } cs.End(err != nil) if err == nil { t.dprintf("put %s: %s\n", rid, d) c <- d } else { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("put %s: %s\n", rid, err) } close(c, err) }() return c } func (t *Rfs) Put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) chan zx.Dir { t.dprintf("put %s %v %d '%s'\n", rid, d, off, pred) msg := &Msg{Op: Tput, Rid: rid, D: d, Off: off, Pred: pred} return t.putrpc(rid, msg, dc) } func (t *Rfs) errrpc(rid, op string, msg *Msg, k int) chan error { t.c.Debug = t.Dbg && VerbDebug c := make(chan error, 1) go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() var cs *zx.CallStat if k >= 0 { cs = t.IOstats.NewCallSize(k, len(raw)) } reqc <- raw close(reqc) <-repc err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("%s %s: %s\n", op, rid, err) } else { t.dprintf("%s %s: ok\n", op, rid) } c <- err close(c, err) cs.End(err != nil) }() return c } func (t *Rfs) Fsys(name string) <-chan error { t.dprintf("fsys %s\n", name) msg := &Msg{Op: Tfsys, Rid: name} return t.errrpc(name, "fsys", msg, -1) } func (t *Rfs) Mkdir(rid string, d zx.Dir) chan error { msg := &Msg{Op: Tmkdir, Rid: rid, D: d} t.dprintf("mkdir %s %v\n", rid, d) return t.errrpc(rid, "mkdir", msg, zx.Smkdir) } func (t *Rfs) Move(from, to string) chan error { t.dprintf("move %s %s \n", from, to) msg := &Msg{Op: Tmove, Rid: from, To: to} return t.errrpc(from, "move", msg, zx.Smove) } func (t *Rfs) Remove(rid string) chan error { t.dprintf("remove %s\n", rid) msg := &Msg{Op: Tremove, Rid: rid} return t.errrpc(rid, "remove", msg, zx.Sremove) } func (t *Rfs) RemoveAll(rid string) chan error { t.dprintf("removeall %s\n", rid) msg := &Msg{Op: Tremoveall, Rid: rid} return t.errrpc(rid, "removeall", msg, zx.Sremoveall) } func (t *Rfs) Wstat(rid string, d zx.Dir) chan error { t.dprintf("wstat %s %v\n", rid, d) msg := &Msg{Op: Twstat, Rid: rid, D: d} return t.errrpc(rid, "wstat", msg, zx.Swstat) } func (t *Rfs) Find(rid, pred, spref, dpref string, depth int) <-chan zx.Dir { t.dprintf("find %s '%s' '%s' '%s' %d\n", rid, pred, spref, dpref, depth) dc := make(chan zx.Dir) msg := &Msg{Op: Tfind, Rid: rid, Pred: pred, Spref: spref, Dpref: dpref, Depth: depth} go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sfind, len(raw)) reqc <- raw close(reqc) some := false for rep := range repc { cs.Send(int64(len(rep))) d, _, _ := zx.UnpackDir(rep) if d != nil { d["addr"] = t.addr d["proto"] = "zx" } if ok := dc <- d; !ok { close(repc, cerror(dc)) break } some = true t.dprintf(rid, "find", "<- %v\n", d) } if !some { dc <- nil } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(dc, err) cs.End(err != nil) }() return dc } func (t *Rfs) FindGet(rid, pred, spref, dpref string, depth int) <-chan zx.DirData { t.dprintf("findget %s '%s' '%s' '%s' %d\n", rid, pred, spref, dpref, depth) dc := make(chan zx.DirData) msg := &Msg{Op: Tfindget, Rid: rid, Pred: pred, Spref: spref, Dpref: dpref, Depth: depth} go func() { reqc, repc := t.c.Rpc() raw := msg.Pack() cs := t.IOstats.NewCallSize(zx.Sfind, len(raw)) reqc <- raw close(reqc) for rep := range repc { cs.Send(int64(len(rep))) d, _, _ := zx.UnpackDir(rep) if d != nil { d["addr"] = t.addr d["proto"] = "zx" } res := zx.DirData{Dir: d} var datc chan []byte if d["err"]=="" && d["type"]=="-" { datc = make(chan []byte) res.Datac = datc } if ok := dc <- res; !ok { close(repc, cerror(dc)) break } t.dprintf(rid, "find", "<- %v\n", d) if datc != nil { for rep := range repc { if len(rep) == 0 { break } if ok := datc <- rep; !ok { continue } } close(datc, cerror(repc)) } } err := cerror(repc) cs.End(err != nil) if err != nil { if isHangup(err) { t.Close(ErrHangUp) } t.dprintf("find %s: %s\n", rid, err) } else { t.dprintf("find %s: ok\n", rid) } close(dc, err) }() return dc }