~moody/ninep

d394458419b1bc3ea43eb8426ccecfc427352ab9 — Jacob Moody a month ago 7b4c048 master
Rework api
Clean up exports, use *Qid for sessions
Dont export R* types, make T*.Respond take the needed args.
Storing Qid pointers reduces the uglyness of FS not being able to
modify the Qid(for example the path).
7 files changed, 367 insertions(+), 372 deletions(-)

M fs.go
M genproto.go
M message_test.go
M proto.go
M srv.go
M srv_example_test.go
M util.go
M fs.go => fs.go +9 -9
@@ 57,7 57,7 @@ type NopFS struct{}
var errNotImpl = errors.New("not implemented")

func (n *NopFS) Attach(t *Tattach) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Walk(cur *Qid, next string) *Qid {


@@ 65,33 65,33 @@ func (n *NopFS) Walk(cur *Qid, next string) *Qid {
}

func (n *NopFS) Create(t *Tcreate, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Open(t *Topen, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Read(t *Tread, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Write(t *Twrite, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Stat(t *Tstat, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Wstat(t *Twstat, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Remove(t *Tremove, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

func (n *NopFS) Clunk(t *Tclunk, q *Qid) {
	t.Respond(nil, errNotImpl)
	t.Err(errNotImpl)
}

M genproto.go => genproto.go +86 -26
@@ 18,7 18,6 @@ var proto = []string{
	"Rversion msize[4] version[s]",
	"Tauth afid[4] uname[s] aname[s]",
	"Rauth Qid",
	"Rerror ename[s]",
	"Tflush oldtag[2]",
	"Rflush",
	"Tattach fid[4] afid[4] uname[s] aname[s]",


@@ 41,6 40,7 @@ var proto = []string{
	"Rstat Dir",
	"Twstat fid[4] Dir",
	"Rwstat",
	"Rerror ename[s]",
}

const (


@@ 233,18 233,19 @@ func (m *mem) Decl() string {
		}
		return out + " []byte"
	case dirT:
		return "Dir"
		return "*Dir"
	case qidT:
		return "Qid"
		return "*Qid"
	}
	panic("missing case")
}

type msg struct {
	Name string
	Typ  string
	Recv string
	Mems []mem
	Name     string
	Typ      string
	Recv     string
	Mems     []mem
	RespMems []mem
}

func (m *msg) IsT() bool {


@@ 254,16 255,59 @@ func (m *msg) IsT() bool {
func (m *msg) Resp() string {
	switch m.Name[0] {
	case 'T':
		return "R" + m.Name[1:]
		return "_R" + m.Name[1:]
	case '_':
		return "_R" + m.Name[2:]
	}
	panic("missing case")
}

func (m *msg) ParseResp(mem []string) {
	for _, e := range mem {
		me := newMem(e)
		me.Name = strings.ToLower(me.Name)
		m.RespMems = append(m.RespMems, me)
	}
}

func (m *msg) RespArgs() string {
	s := &strings.Builder{}
	for _, e := range m.RespMems {
		decl := e.Decl()
		switch decl {
		case "*Qid":
			decl = "qid *Qid"
		case "*Dir":
			decl = "dir *Dir"
		}
		s.WriteString(fmt.Sprintf("%s,", decl))
	}
	ss := s.String()
	if len(m.RespMems) > 1 {
		ss = ss[:len(ss)-1]
	}
	return ss
}

func (m *msg) NewResp() string {
	s := strings.Builder{}
	s.WriteString("&")
	s.WriteString(m.Resp())
	s.WriteString("{")
	s.WriteString("t.tg,")
	for i, e := range m.RespMems {
		s.WriteString(e.Name)
		if i != len(m.RespMems)-1 {
			s.WriteString(", ")
		}
	}
	s.WriteString("}")
	return s.String()
}

func newMsg(s string, mem []string) *msg {
	typ := strings.ToLower(s)
	if strings.Contains(s, "walk") || strings.Contains(s, "flush") {
	if s[0] == 'R' || strings.Contains(s, "walk") || strings.Contains(s, "flush") || strings.Contains(s, "version") {
		s = "_" + s
	}
	m := &msg{Name: s, Typ: typ, Recv: typ[:1]}


@@ 341,12 385,16 @@ return s`

func (m *msg) Print() string {
	s := &strings.Builder{}
	name := m.Name
	if name[0] == '_' {
		name = name[1:]
	}
	s.WriteString(`return fmt.Sprintf("`)
	if len(m.Mems) == 0 {
		s.WriteString(fmt.Sprintf(`%s{tag: %%v}", %s.tg)`, m.Name, m.Recv))
		s.WriteString(fmt.Sprintf(`%s{tag: %%v}", %s.tg)`, name, m.Recv))
		return s.String()
	}
	s.WriteString(m.Name + "{tag: %v, ")
	s.WriteString(name + "{tag: %v, ")
	for i, e := range m.Mems {
		if i == len(m.Mems)-1 {
			s.WriteString(fmt.Sprintf("%s: %%v}\"", e.Name))


@@ 370,21 418,16 @@ type {{.Name}} struct {
	{{.Decl}}{{end}}
}
{{if .IsT}}
func ({{.Recv}} *{{.Name}}) Respond(r *{{.Resp}}, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func ({{.Recv}} *{{.Name}}) Respond({{.RespArgs}}) {
	t.rf(t, {{.NewResp}}, "")
}
func ({{.Recv}} *{{.Name}}) RespondString(r *{{.Resp}}, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func ({{.Recv}} *{{.Name}}) Err(err error) {
	t.rf(t, nil, err.Error())
}

func ({{.Recv}} *{{.Name}}) StrErr(err string) {
	t.rf(t, nil, err)
}
{{end}}
func ({{.Recv}} *{{.Name}}) size() int { {{.Size}} }


@@ 409,15 452,32 @@ func main() {
	fmt.Fprintln(b, "//This file is autogenerated by genproto.go -- DO NOT EDIT\n")
	fmt.Fprintln(b, `import "encoding/binary"`)
	fmt.Fprintln(b, `import "fmt"`+"\n")
	var lastMesg *msg
	for _, m := range proto {
		s := strings.Fields(m)
		err := tmpl.Execute(b, newMsg(s[0], s[1:]))
		me := newMsg(s[0], s[1:])
		if me.Typ == "rerror" {
			goto gen
		}
		if me.Typ[0] == 'r' {
			lastMesg.ParseResp(s[1:])
			err := tmpl.Execute(b, lastMesg)
			if err != nil {
				log.Fatal(err)
			}
		} else if me.Typ[0] == 't' {
			lastMesg = me
			continue
		}
	gen:
		err := tmpl.Execute(b, me)
		if err != nil {
			log.Fatal(err)
		}
	}
	buf, err := format.Source(b.Bytes())
	if err != nil {
		fmt.Println(string(b.Bytes()))
		log.Fatal(err)
	}
	f, err := os.Create("proto.go")

M message_test.go => message_test.go +2 -2
@@ 6,7 6,7 @@ import (
)

func TestVersion(t *testing.T) {
	v := &Tversion{rf: nil, tg: 0, Msize: 8192, Version: Ninep2000}
	v := &_Tversion{rf: nil, tg: 0, Msize: 8192, Version: Ninep2000}
	b := make([]byte, v.size())
	v.encode(b)



@@ 17,7 17,7 @@ func TestVersion(t *testing.T) {
		t.Fatal("mismatch from plan9 generated")
	}

	v2 := &Rversion{}
	v2 := &_Rversion{}
	v2.decode(b)

	if v.Version != v2.Version {

M proto.go => proto.go +238 -303
@@ 5,7 5,7 @@ package ninep
import "encoding/binary"
import "fmt"

type Tversion struct {
type _Tversion struct {
	tg uint16
	rf respFunc



@@ 13,35 13,30 @@ type Tversion struct {
	Version string
}

func (t *Tversion) Respond(r *Rversion, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *_Tversion) Respond(msize uint32, version string) {
	t.rf(t, &_Rversion{t.tg, msize, version}, "")
}
func (t *Tversion) RespondString(r *Rversion, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *_Tversion) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tversion) size() int   { return 4 + 2 + len(t.Version) }
func (t *Tversion) typ() byte   { return tversion }
func (t *Tversion) tag() uint16 { return t.tg }
func (t *_Tversion) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *_Tversion) size() int   { return 4 + 2 + len(t.Version) }
func (t *_Tversion) typ() byte   { return tversion }
func (t *_Tversion) tag() uint16 { return t.tg }

func (t *Tversion) encode(b []byte) {
func (t *_Tversion) encode(b []byte) {
	binary.LittleEndian.PutUint32(b[0:], t.Msize)
	var n int
	b = b[4:]
	n = putStr(b, t.Version)
	b = b[n:]
}
func (t *Tversion) decode(b []byte) {
func (t *_Tversion) decode(b []byte) {
	t.Msize = binary.LittleEndian.Uint32(b[0:])
	var n int
	b = b[4:]


@@ 49,29 44,29 @@ func (t *Tversion) decode(b []byte) {
	b = b[n:]
}

func (t *Tversion) String() string {
func (t *_Tversion) String() string {
	return fmt.Sprintf("Tversion{tag: %v, Msize: %v, Version: %v}", t.tg, t.Msize, t.Version)
}

type Rversion struct {
type _Rversion struct {
	tg uint16

	Msize   uint32
	Version string
}

func (r *Rversion) size() int   { return 4 + 2 + len(r.Version) }
func (r *Rversion) typ() byte   { return rversion }
func (r *Rversion) tag() uint16 { return r.tg }
func (r *_Rversion) size() int   { return 4 + 2 + len(r.Version) }
func (r *_Rversion) typ() byte   { return rversion }
func (r *_Rversion) tag() uint16 { return r.tg }

func (r *Rversion) encode(b []byte) {
func (r *_Rversion) encode(b []byte) {
	binary.LittleEndian.PutUint32(b[0:], r.Msize)
	var n int
	b = b[4:]
	n = putStr(b, r.Version)
	b = b[n:]
}
func (r *Rversion) decode(b []byte) {
func (r *_Rversion) decode(b []byte) {
	r.Msize = binary.LittleEndian.Uint32(b[0:])
	var n int
	b = b[4:]


@@ 79,7 74,7 @@ func (r *Rversion) decode(b []byte) {
	b = b[n:]
}

func (r *Rversion) String() string {
func (r *_Rversion) String() string {
	return fmt.Sprintf("Rversion{tag: %v, Msize: %v, Version: %v}", r.tg, r.Msize, r.Version)
}



@@ 92,21 87,16 @@ type Tauth struct {
	Aname string
}

func (t *Tauth) Respond(r *Rauth, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tauth) Respond(qid *Qid) {
	t.rf(t, &_Rauth{t.tg, qid}, "")
}
func (t *Tauth) RespondString(r *Rauth, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tauth) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tauth) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tauth) size() int   { return 4 + 2 + len(t.Uname) + 2 + len(t.Aname) }


@@ 136,54 126,27 @@ func (t *Tauth) String() string {
	return fmt.Sprintf("Tauth{tag: %v, afid: %v, Uname: %v, Aname: %v}", t.tg, t.afid, t.Uname, t.Aname)
}

type Rauth struct {
type _Rauth struct {
	tg uint16

	Qid
	*Qid
}

func (r *Rauth) size() int   { return r.Qid.size() }
func (r *Rauth) typ() byte   { return rauth }
func (r *Rauth) tag() uint16 { return r.tg }
func (r *_Rauth) size() int   { return r.Qid.size() }
func (r *_Rauth) typ() byte   { return rauth }
func (r *_Rauth) tag() uint16 { return r.tg }

func (r *Rauth) encode(b []byte) {
func (r *_Rauth) encode(b []byte) {
	r.Qid.encode(b[0:])
}
func (r *Rauth) decode(b []byte) {
func (r *_Rauth) decode(b []byte) {
	r.Qid.decode(b[0:])
}

func (r *Rauth) String() string {
func (r *_Rauth) String() string {
	return fmt.Sprintf("Rauth{tag: %v, Qid: %v}", r.tg, r.Qid)
}

type Rerror struct {
	tg uint16

	Ename string
}

func (r *Rerror) size() int   { return 2 + len(r.Ename) }
func (r *Rerror) typ() byte   { return rerror }
func (r *Rerror) tag() uint16 { return r.tg }

func (r *Rerror) encode(b []byte) {
	var n int
	b = b[0:]
	n = putStr(b, r.Ename)
	b = b[n:]
}
func (r *Rerror) decode(b []byte) {
	var n int
	b = b[0:]
	n, r.Ename = getStr(b)
	b = b[n:]
}

func (r *Rerror) String() string {
	return fmt.Sprintf("Rerror{tag: %v, Ename: %v}", r.tg, r.Ename)
}

type _Tflush struct {
	tg uint16
	rf respFunc


@@ 191,21 154,16 @@ type _Tflush struct {
	Oldtag uint16
}

func (t *_Tflush) Respond(r *_Rflush, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *_Tflush) Respond() {
	t.rf(t, &_Rflush{t.tg}, "")
}
func (t *_Tflush) RespondString(r *_Rflush, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *_Tflush) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *_Tflush) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *_Tflush) size() int   { return 2 }


@@ 220,7 178,7 @@ func (t *_Tflush) decode(b []byte) {
}

func (t *_Tflush) String() string {
	return fmt.Sprintf("_Tflush{tag: %v, Oldtag: %v}", t.tg, t.Oldtag)
	return fmt.Sprintf("Tflush{tag: %v, Oldtag: %v}", t.tg, t.Oldtag)
}

type _Rflush struct {


@@ 237,7 195,7 @@ func (r *_Rflush) decode(b []byte) {
}

func (r *_Rflush) String() string {
	return fmt.Sprintf("_Rflush{tag: %v}", r.tg)
	return fmt.Sprintf("Rflush{tag: %v}", r.tg)
}

type Tattach struct {


@@ 250,21 208,16 @@ type Tattach struct {
	Aname string
}

func (t *Tattach) Respond(r *Rattach, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tattach) Respond(qid *Qid) {
	t.rf(t, &_Rattach{t.tg, qid}, "")
}
func (t *Tattach) RespondString(r *Rattach, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tattach) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tattach) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tattach) size() int   { return 4 + 4 + 2 + len(t.Uname) + 2 + len(t.Aname) }


@@ 296,24 249,24 @@ func (t *Tattach) String() string {
	return fmt.Sprintf("Tattach{tag: %v, fid: %v, afid: %v, Uname: %v, Aname: %v}", t.tg, t.fid, t.afid, t.Uname, t.Aname)
}

type Rattach struct {
type _Rattach struct {
	tg uint16

	Qid
	*Qid
}

func (r *Rattach) size() int   { return r.Qid.size() }
func (r *Rattach) typ() byte   { return rattach }
func (r *Rattach) tag() uint16 { return r.tg }
func (r *_Rattach) size() int   { return r.Qid.size() }
func (r *_Rattach) typ() byte   { return rattach }
func (r *_Rattach) tag() uint16 { return r.tg }

func (r *Rattach) encode(b []byte) {
func (r *_Rattach) encode(b []byte) {
	r.Qid.encode(b[0:])
}
func (r *Rattach) decode(b []byte) {
func (r *_Rattach) decode(b []byte) {
	r.Qid.decode(b[0:])
}

func (r *Rattach) String() string {
func (r *_Rattach) String() string {
	return fmt.Sprintf("Rattach{tag: %v, Qid: %v}", r.tg, r.Qid)
}



@@ 326,21 279,16 @@ type _Twalk struct {
	Names  []string
}

func (t *_Twalk) Respond(r *_Rwalk, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *_Twalk) Respond(qid []Qid) {
	t.rf(t, &_Rwalk{t.tg, qid}, "")
}
func (t *_Twalk) RespondString(r *_Rwalk, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *_Twalk) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *_Twalk) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *_Twalk) size() int {


@@ 377,7 325,7 @@ func (t *_Twalk) decode(b []byte) {
}

func (t *_Twalk) String() string {
	return fmt.Sprintf("_Twalk{tag: %v, fid: %v, newfid: %v, Names: %v}", t.tg, t.fid, t.newfid, t.Names)
	return fmt.Sprintf("Twalk{tag: %v, fid: %v, newfid: %v, Names: %v}", t.tg, t.fid, t.newfid, t.Names)
}

type _Rwalk struct {


@@ 410,7 358,7 @@ func (r *_Rwalk) decode(b []byte) {
}

func (r *_Rwalk) String() string {
	return fmt.Sprintf("_Rwalk{tag: %v, Qid: %v}", r.tg, r.Qid)
	return fmt.Sprintf("Rwalk{tag: %v, Qid: %v}", r.tg, r.Qid)
}

type Topen struct {


@@ 421,21 369,16 @@ type Topen struct {
	Mode byte
}

func (t *Topen) Respond(r *Ropen, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Topen) Respond(qid *Qid, iounit uint32) {
	t.rf(t, &_Ropen{t.tg, qid, iounit}, "")
}
func (t *Topen) RespondString(r *Ropen, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Topen) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Topen) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Topen) size() int   { return 4 + 1 }


@@ 455,27 398,27 @@ func (t *Topen) String() string {
	return fmt.Sprintf("Topen{tag: %v, fid: %v, Mode: %v}", t.tg, t.fid, t.Mode)
}

type Ropen struct {
type _Ropen struct {
	tg uint16

	Qid
	*Qid
	Iounit uint32
}

func (r *Ropen) size() int   { return r.Qid.size() + 4 }
func (r *Ropen) typ() byte   { return ropen }
func (r *Ropen) tag() uint16 { return r.tg }
func (r *_Ropen) size() int   { return r.Qid.size() + 4 }
func (r *_Ropen) typ() byte   { return ropen }
func (r *_Ropen) tag() uint16 { return r.tg }

func (r *Ropen) encode(b []byte) {
func (r *_Ropen) encode(b []byte) {
	r.Qid.encode(b[0:])
	binary.LittleEndian.PutUint32(b[13:], r.Iounit)
}
func (r *Ropen) decode(b []byte) {
func (r *_Ropen) decode(b []byte) {
	r.Qid.decode(b[0:])
	r.Iounit = binary.LittleEndian.Uint32(b[0:])
}

func (r *Ropen) String() string {
func (r *_Ropen) String() string {
	return fmt.Sprintf("Ropen{tag: %v, Qid: %v, Iounit: %v}", r.tg, r.Qid, r.Iounit)
}



@@ 489,21 432,16 @@ type Tcreate struct {
	Mode byte
}

func (t *Tcreate) Respond(r *Rcreate, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tcreate) Respond(qid *Qid, iounit uint32) {
	t.rf(t, &_Rcreate{t.tg, qid, iounit}, "")
}
func (t *Tcreate) RespondString(r *Rcreate, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tcreate) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tcreate) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tcreate) size() int   { return 4 + 2 + len(t.Name) + 4 + 1 }


@@ 533,27 471,27 @@ func (t *Tcreate) String() string {
	return fmt.Sprintf("Tcreate{tag: %v, fid: %v, Name: %v, Perm: %v, Mode: %v}", t.tg, t.fid, t.Name, t.Perm, t.Mode)
}

type Rcreate struct {
type _Rcreate struct {
	tg uint16

	Qid
	*Qid
	Iounit uint32
}

func (r *Rcreate) size() int   { return r.Qid.size() + 4 }
func (r *Rcreate) typ() byte   { return rcreate }
func (r *Rcreate) tag() uint16 { return r.tg }
func (r *_Rcreate) size() int   { return r.Qid.size() + 4 }
func (r *_Rcreate) typ() byte   { return rcreate }
func (r *_Rcreate) tag() uint16 { return r.tg }

func (r *Rcreate) encode(b []byte) {
func (r *_Rcreate) encode(b []byte) {
	r.Qid.encode(b[0:])
	binary.LittleEndian.PutUint32(b[13:], r.Iounit)
}
func (r *Rcreate) decode(b []byte) {
func (r *_Rcreate) decode(b []byte) {
	r.Qid.decode(b[0:])
	r.Iounit = binary.LittleEndian.Uint32(b[0:])
}

func (r *Rcreate) String() string {
func (r *_Rcreate) String() string {
	return fmt.Sprintf("Rcreate{tag: %v, Qid: %v, Iounit: %v}", r.tg, r.Qid, r.Iounit)
}



@@ 566,21 504,16 @@ type Tread struct {
	Count  uint32
}

func (t *Tread) Respond(r *Rread, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tread) Respond(data []byte) {
	t.rf(t, &_Rread{t.tg, data}, "")
}
func (t *Tread) RespondString(r *Rread, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tread) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tread) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tread) size() int   { return 4 + 8 + 4 }


@@ 602,25 535,25 @@ func (t *Tread) String() string {
	return fmt.Sprintf("Tread{tag: %v, fid: %v, Offset: %v, Count: %v}", t.tg, t.fid, t.Offset, t.Count)
}

type Rread struct {
type _Rread struct {
	tg uint16

	Data []byte
}

func (r *Rread) size() int   { return 4 + len(r.Data) }
func (r *Rread) typ() byte   { return rread }
func (r *Rread) tag() uint16 { return r.tg }
func (r *_Rread) size() int   { return 4 + len(r.Data) }
func (r *_Rread) typ() byte   { return rread }
func (r *_Rread) tag() uint16 { return r.tg }

func (r *Rread) encode(b []byte) {
func (r *_Rread) encode(b []byte) {
	binary.LittleEndian.PutUint32(b[0:], uint32(len(r.Data)))
	copy(b[4:], r.Data)
}
func (r *Rread) decode(b []byte) {
func (r *_Rread) decode(b []byte) {
	r.Data = b[4:]
}

func (r *Rread) String() string {
func (r *_Rread) String() string {
	return fmt.Sprintf("Rread{tag: %v, Data: %v}", r.tg, r.Data)
}



@@ 633,21 566,16 @@ type Twrite struct {
	Data   []byte
}

func (t *Twrite) Respond(r *Rwrite, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Twrite) Respond(count uint32) {
	t.rf(t, &_Rwrite{t.tg, count}, "")
}
func (t *Twrite) RespondString(r *Rwrite, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Twrite) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Twrite) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Twrite) size() int   { return 4 + 8 + 4 + len(t.Data) }


@@ 670,24 598,24 @@ func (t *Twrite) String() string {
	return fmt.Sprintf("Twrite{tag: %v, fid: %v, Offset: %v, Data: %v}", t.tg, t.fid, t.Offset, t.Data)
}

type Rwrite struct {
type _Rwrite struct {
	tg uint16

	Count uint32
}

func (r *Rwrite) size() int   { return 4 }
func (r *Rwrite) typ() byte   { return rwrite }
func (r *Rwrite) tag() uint16 { return r.tg }
func (r *_Rwrite) size() int   { return 4 }
func (r *_Rwrite) typ() byte   { return rwrite }
func (r *_Rwrite) tag() uint16 { return r.tg }

func (r *Rwrite) encode(b []byte) {
func (r *_Rwrite) encode(b []byte) {
	binary.LittleEndian.PutUint32(b[0:], r.Count)
}
func (r *Rwrite) decode(b []byte) {
func (r *_Rwrite) decode(b []byte) {
	r.Count = binary.LittleEndian.Uint32(b[0:])
}

func (r *Rwrite) String() string {
func (r *_Rwrite) String() string {
	return fmt.Sprintf("Rwrite{tag: %v, Count: %v}", r.tg, r.Count)
}



@@ 698,21 626,16 @@ type Tclunk struct {
	fid uint32
}

func (t *Tclunk) Respond(r *Rclunk, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tclunk) Respond() {
	t.rf(t, &_Rclunk{t.tg}, "")
}
func (t *Tclunk) RespondString(r *Rclunk, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tclunk) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tclunk) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tclunk) size() int   { return 4 }


@@ 730,20 653,20 @@ func (t *Tclunk) String() string {
	return fmt.Sprintf("Tclunk{tag: %v, fid: %v}", t.tg, t.fid)
}

type Rclunk struct {
type _Rclunk struct {
	tg uint16
}

func (r *Rclunk) size() int   { return 0 }
func (r *Rclunk) typ() byte   { return rclunk }
func (r *Rclunk) tag() uint16 { return r.tg }
func (r *_Rclunk) size() int   { return 0 }
func (r *_Rclunk) typ() byte   { return rclunk }
func (r *_Rclunk) tag() uint16 { return r.tg }

func (r *Rclunk) encode(b []byte) {
func (r *_Rclunk) encode(b []byte) {
}
func (r *Rclunk) decode(b []byte) {
func (r *_Rclunk) decode(b []byte) {
}

func (r *Rclunk) String() string {
func (r *_Rclunk) String() string {
	return fmt.Sprintf("Rclunk{tag: %v}", r.tg)
}



@@ 754,21 677,16 @@ type Tremove struct {
	fid uint32
}

func (t *Tremove) Respond(r *Rremove, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tremove) Respond() {
	t.rf(t, &_Rremove{t.tg}, "")
}
func (t *Tremove) RespondString(r *Rremove, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tremove) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tremove) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tremove) size() int   { return 4 }


@@ 786,20 704,20 @@ func (t *Tremove) String() string {
	return fmt.Sprintf("Tremove{tag: %v, fid: %v}", t.tg, t.fid)
}

type Rremove struct {
type _Rremove struct {
	tg uint16
}

func (r *Rremove) size() int   { return 0 }
func (r *Rremove) typ() byte   { return rremove }
func (r *Rremove) tag() uint16 { return r.tg }
func (r *_Rremove) size() int   { return 0 }
func (r *_Rremove) typ() byte   { return rremove }
func (r *_Rremove) tag() uint16 { return r.tg }

func (r *Rremove) encode(b []byte) {
func (r *_Rremove) encode(b []byte) {
}
func (r *Rremove) decode(b []byte) {
func (r *_Rremove) decode(b []byte) {
}

func (r *Rremove) String() string {
func (r *_Rremove) String() string {
	return fmt.Sprintf("Rremove{tag: %v}", r.tg)
}



@@ 810,21 728,16 @@ type Tstat struct {
	fid uint32
}

func (t *Tstat) Respond(r *Rstat, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Tstat) Respond(dir *Dir) {
	t.rf(t, &_Rstat{t.tg, dir}, "")
}
func (t *Tstat) RespondString(r *Rstat, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Tstat) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Tstat) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Tstat) size() int   { return 4 }


@@ 842,25 755,25 @@ func (t *Tstat) String() string {
	return fmt.Sprintf("Tstat{tag: %v, fid: %v}", t.tg, t.fid)
}

type Rstat struct {
type _Rstat struct {
	tg uint16

	Dir
	*Dir
}

func (r *Rstat) size() int   { return 2 + r.Dir.size() }
func (r *Rstat) typ() byte   { return rstat }
func (r *Rstat) tag() uint16 { return r.tg }
func (r *_Rstat) size() int   { return 2 + r.Dir.size() }
func (r *_Rstat) typ() byte   { return rstat }
func (r *_Rstat) tag() uint16 { return r.tg }

func (r *Rstat) encode(b []byte) {
func (r *_Rstat) encode(b []byte) {
	binary.LittleEndian.PutUint16(b[0:], uint16(r.Dir.size()))
	r.Dir.encode(b[2:])
}
func (r *Rstat) decode(b []byte) {
func (r *_Rstat) decode(b []byte) {
	r.Dir.decode(b[2:])
}

func (r *Rstat) String() string {
func (r *_Rstat) String() string {
	return fmt.Sprintf("Rstat{tag: %v, Dir: %v}", r.tg, r.Dir)
}



@@ 869,24 782,19 @@ type Twstat struct {
	rf respFunc

	fid uint32
	Dir
	*Dir
}

func (t *Twstat) Respond(r *Rwstat, err error) {
	if r != nil {
		r.tg = t.tg
	}
	var s string
	if err != nil {
		s = err.Error()
	}
	t.rf(t, r, s)
func (t *Twstat) Respond() {
	t.rf(t, &_Rwstat{t.tg}, "")
}
func (t *Twstat) RespondString(r *Rwstat, err string) {
	if r != nil {
		r.tg = t.tg
	}
	t.rf(t, r, err)

func (t *Twstat) Err(err error) {
	t.rf(t, nil, err.Error())
}

func (t *Twstat) StrErr(err string) {
	t.rf(t, nil, err)
}

func (t *Twstat) size() int   { return 4 + 2 + t.Dir.size() }


@@ 907,19 815,46 @@ func (t *Twstat) String() string {
	return fmt.Sprintf("Twstat{tag: %v, fid: %v, Dir: %v}", t.tg, t.fid, t.Dir)
}

type Rwstat struct {
type _Rwstat struct {
	tg uint16
}

func (r *Rwstat) size() int   { return 0 }
func (r *Rwstat) typ() byte   { return rwstat }
func (r *Rwstat) tag() uint16 { return r.tg }
func (r *_Rwstat) size() int   { return 0 }
func (r *_Rwstat) typ() byte   { return rwstat }
func (r *_Rwstat) tag() uint16 { return r.tg }

func (r *Rwstat) encode(b []byte) {
func (r *_Rwstat) encode(b []byte) {
}
func (r *Rwstat) decode(b []byte) {
func (r *_Rwstat) decode(b []byte) {
}

func (r *Rwstat) String() string {
func (r *_Rwstat) String() string {
	return fmt.Sprintf("Rwstat{tag: %v}", r.tg)
}

type _Rerror struct {
	tg uint16

	Ename string
}

func (r *_Rerror) size() int   { return 2 + len(r.Ename) }
func (r *_Rerror) typ() byte   { return rerror }
func (r *_Rerror) tag() uint16 { return r.tg }

func (r *_Rerror) encode(b []byte) {
	var n int
	b = b[0:]
	n = putStr(b, r.Ename)
	b = b[n:]
}
func (r *_Rerror) decode(b []byte) {
	var n int
	b = b[0:]
	n, r.Ename = getStr(b)
	b = b[n:]
}

func (r *_Rerror) String() string {
	return fmt.Sprintf("Rerror{tag: %v, Ename: %v}", r.tg, r.Ename)
}

M srv.go => srv.go +24 -24
@@ 18,7 18,7 @@ type Srv struct {
	rf respFunc

	//fid->Qid management
	fm  map[uint32]Qid
	fm  map[uint32]*Qid
	fml *sync.RWMutex

	//req management


@@ 41,7 41,7 @@ func NewSrv(fsf FSMaker) *Srv {
	s := &Srv{
		ch: make(chan message),

		fm:  make(map[uint32]Qid),
		fm:  make(map[uint32]*Qid),
		fml: &sync.RWMutex{},

		flushed: make(map[uint16]struct{}),


@@ 108,10 108,10 @@ func (s *Srv) getSess(t message, fid uint32) (*Qid, FS) {
		//fool me twice, shame on me
		panic("inconsistant state between qid and sess mapping")
	}
	return &qid, fs
	return qid, fs
}

func (s *Srv) setQid(fid uint32, q Qid) {
func (s *Srv) setQid(fid uint32, q *Qid) {
	s.fml.Lock()
	s.fm[fid] = q
	s.fml.Unlock()


@@ 157,21 157,21 @@ func (s *Srv) respFunc() respFunc {
		}
		s.flushl.Unlock()
		if err != "" {
			s.ch <- &Rerror{tg: t.tag(), Ename: err}
			s.ch <- &_Rerror{tg: t.tag(), Ename: err}
			return
		}
		switch v := r.(type) {
		case *Rversion, *_Rflush, *Rread, *Rwrite, *Rclunk, *Rremove, *Rstat, *Rwstat:
		case *Rattach:
		case *_Rversion, *_Rflush, *_Rread, *_Rwrite, *_Rclunk, *_Rremove, *_Rstat, *_Rwstat:
		case *_Rattach:
			ta := t.(*Tattach)
			s.setQid(ta.fid, v.Qid)
		case *Rauth:
		case *_Rauth:
			ta := t.(*Tauth)
			s.setQid(ta.afid, v.Qid)
		case *Rcreate:
		case *_Rcreate:
			tc := t.(*Tcreate)
			s.setQid(tc.fid, v.Qid)
		case *Ropen:
		case *_Ropen:
			tp := t.(*Topen)
			s.setQid(tp.fid, v.Qid)
		case *_Rwalk:


@@ 200,13 200,13 @@ func (s *Srv) readLoop(from io.Reader) {
		}
		switch typ {
		case tversion:
			t := &Tversion{rf: s.rf, tg: tag}
			t := &_Tversion{rf: s.rf, tg: tag}
			t.decode(b)
			s.version(t)
		case tauth:
			t := &Tauth{rf: s.rf, tg: tag}
			t.decode(b)
			t.RespondString(nil, "authentication not required")
			t.StrErr("authentication not required")
		case tattach:
			t := &Tattach{rf: s.rf, tg: tag}
			t.decode(b)


@@ 270,7 270,7 @@ func (s *Srv) readLoop(from io.Reader) {
			s.flushl.Lock()
			s.flushed[t.tg] = struct{}{}
			s.flushl.Unlock()
			t.Respond(&_Rflush{}, nil)
			t.Respond()
		}
	}
}


@@ 278,17 278,17 @@ func (s *Srv) readLoop(from io.Reader) {
const notag = 65535
const Ninep2000 = "9P2000"

func (s *Srv) version(t *Tversion) {
func (s *Srv) version(t *_Tversion) {
	if t.Version != Ninep2000 {
		t.RespondString(nil, "version != 9P2000")
		t.StrErr("version != 9P2000")
		return
	}
	if t.tg != notag {
		t.RespondString(nil, "version: protocol botch: tag != NOTAG")
		t.StrErr("version: protocol botch: tag != NOTAG")
		return
	}
	s.msize = int(t.Msize)
	t.Respond(&Rversion{Version: t.Version, Msize: t.Msize}, nil)
	t.Respond(t.Msize, t.Version)
}

func (s *Srv) twalk(t *_Twalk) {


@@ 296,17 296,17 @@ func (s *Srv) twalk(t *_Twalk) {
	start, ok := s.fm[t.fid]
	s.fml.RUnlock()
	if !ok {
		t.RespondString(nil, "start fid invalid")
		t.StrErr("start fid invalid")
		return
	}
	s.sessl.RLock()
	fs, ok := s.sessions[t.fid]
	s.sessl.RUnlock()
	if !ok {
		t.RespondString(nil, "start fid invalid")
		t.StrErr("start fid invalid")
		return
	}
	cur := &start
	cur := start
	var out []Qid
	for i := range t.Names {
		n := fs.Walk(cur, t.Names[i])


@@ 316,7 316,7 @@ func (s *Srv) twalk(t *_Twalk) {
		out = append(out, *n)
		cur = n
	}
	t.Respond(&_Rwalk{Qid: out}, nil)
	t.Respond(out)
}

func (s *Srv) rwalk(t *_Twalk, r *_Rwalk) {


@@ 324,7 324,7 @@ func (s *Srv) rwalk(t *_Twalk, r *_Rwalk) {
	os, ok := s.sessions[t.fid]
	if !ok {
		s.sessl.Unlock()
		s.ch <- &Rerror{tg: t.tg, Ename: "walk: oldfid does not exist"}
		s.ch <- &_Rerror{tg: t.tg, Ename: "walk: oldfid does not exist"}
		return
	}
	s.sessions[t.newfid] = os


@@ 334,13 334,13 @@ func (s *Srv) rwalk(t *_Twalk, r *_Rwalk) {
		oq, ok := s.fm[t.fid]
		if !ok {
			s.fml.Unlock()
			s.ch <- &Rerror{tg: t.tg, Ename: "walk: oldfid does not exist"}
			s.ch <- &_Rerror{tg: t.tg, Ename: "walk: oldfid does not exist"}
			return
		}
		s.fm[t.newfid] = oq
	} else {
		newq := r.Qid[len(r.Qid)-1]
		s.fm[t.newfid] = newq
		s.fm[t.newfid] = &newq
	}
	s.fml.Unlock()
	s.ch <- r

M srv_example_test.go => srv_example_test.go +6 -6
@@ 37,7 37,7 @@ func (e *myfs) Attach(t *ninep.Tattach) {
		Gid:  "moody",
		Muid: "moody",
	}
	t.Respond(&ninep.Rattach{Qid: e.rootD.Qid}, nil)
	t.Respond(&e.rootD.Qid)
}

func (e *myfs) Walk(cur *ninep.Qid, next string) *ninep.Qid {


@@ 48,7 48,7 @@ func (e *myfs) Walk(cur *ninep.Qid, next string) *ninep.Qid {
}

func (e *myfs) Open(t *ninep.Topen, q *ninep.Qid) {
	t.Respond(&ninep.Ropen{Qid: *q, Iounit: 8192}, nil)
	t.Respond(q, 8192)
}

var errNoFile = errors.New("no such file or directory")


@@ 60,18 60,18 @@ func (e *myfs) Read(t *ninep.Tread, q *ninep.Qid) {
	case 1:
		ninep.ReadBuf(t, e.msg)
	default:
		t.Respond(nil, errNoFile)
		t.Err(errNoFile)
	}
}

func (e *myfs) Stat(t *ninep.Tstat, q *ninep.Qid) {
	switch q.Path {
	case 0:
		t.Respond(&ninep.Rstat{Dir: e.rootD}, nil)
		t.Respond(&e.rootD)
	case 1:
		t.Respond(&ninep.Rstat{Dir: e.fileD}, nil)
		t.Respond(&e.fileD)
	default:
		t.Respond(nil, errNoFile)
		t.Err(errNoFile)
	}
}


M util.go => util.go +2 -2
@@ 22,13 22,13 @@ func ReadBuf(t *Tread, b []byte) {
	count := int(t.Count)
	off := int(t.Offset)
	if off >= len(b) {
		t.Respond(&Rread{Data: []byte{}}, nil)
		t.Respond([]byte{})
		return
	}
	if off+count > len(b) {
		count = len(b) - off
	}
	t.Respond(&Rread{Data: b[off : off+count]}, nil)
	t.Respond(b[off : off+count])
}

//ReadDir is a helper function that