Commit Diff


commit - 499f8c59005e11c0b5590adabe8b660c4a4cf1cb
commit + e9f5e41480fec822e81050643644fd58a98ac861
blob - 081bacb99c65174f24ce8108cfa6eebc7219e27e
blob + f1889d8ce531e8e636d504b713ea89ca3146a979
--- encoding.go
+++ encoding.go
@@ -17,6 +17,23 @@ type encoder struct {
 func (e *encoder) encode(vs ...interface{}) error {
 	for _, v := range vs {
 		switch v := v.(type) {
+		case *[]string:
+			if err := e.encode(*v); err != nil {
+				return err
+			}
+		case []string:
+			if err := e.encode(uint16(len(v))); err != nil {
+				return err
+			}
+
+			var elements []interface{}
+			for _, e := range v {
+				elements = append(elements, e)
+			}
+
+			if err := e.encode(elements...); err != nil {
+				return err
+			}
 		case *string:
 			if err := e.encode(*v); err != nil {
 				return err
@@ -73,7 +90,7 @@ func (d *decoder) decode(vs ...interface{}) error {
 			var ll uint16
 
 			// implement string[s] encoding
-			if err := binary.Read(d.rd, binary.LittleEndian, &ll); err != nil {
+			if err := d.decode(&ll); err != nil {
 				return err
 			}
 
@@ -89,6 +106,22 @@ func (d *decoder) decode(vs ...interface{}) error {
 			}
 
 			*v = string(b)
+		case *[]string:
+			var ll uint16
+
+			if err := d.decode(&ll); err != nil {
+				return err
+			}
+
+			elements := make([]interface{}, int(ll))
+			*v = make([]string, int(ll))
+			for i := range elements {
+				elements[i] = &(*v)[i]
+			}
+
+			if err := d.decode(elements...); err != nil {
+				return err
+			}
 		case *Fcall:
 			var size uint32
 			if err := d.decode(&size, &v.Type, &v.Tag); err != nil {
@@ -139,6 +172,16 @@ func size9p(vs ...interface{}) uint32 {
 			s += uint32(binary.Size(uint16(0)) + len(*v))
 		case string:
 			s += uint32(binary.Size(uint16(0)) + len(v))
+		case *[]string:
+			s += size9p(*v)
+		case []string:
+			s += size9p(uint16(0))
+			elements := make([]interface{}, len(v))
+			for i := range elements {
+				elements[i] = v[i]
+			}
+
+			s += size9p(elements...)
 		case Message:
 			// walk the fields of the message to get the total size. we just
 			// use the field order from the message struct. We may add tag
@@ -150,18 +193,14 @@ func size9p(vs ...interface{}) uint32 {
 				// return 0 and have the rest of the package do the right
 				// thing. For now, we do this, but may want to panic until
 				// things are stable.
-				return 0
+				panic(err)
 			}
 
 			s += size9p(elements...)
 		case Fcall:
-			s += size9p(v.Type, v.Tag, v.Message)
+			s += size9p(uint32(0), v.Type, v.Tag, v.Message)
 		case *Fcall:
-			// Calculates the total size of the fcall, excluding the size
-			// header, which is handled exernally. The result of
-			// (*Fcall).MarshalBinary will have len(p) == the result of this
-			// branch. The value should be
-			s += size9p(v.Type, v.Tag, v.Message)
+			s += size9p(*v)
 		default:
 			s += uint32(binary.Size(v))
 		}
blob - 074f520e9f040f5f136f3dec00b7db9a713be4f1
blob + fb38ea4090dfd47997571c4808dcd1bf418408b6
--- encoding_test.go
+++ encoding_test.go
@@ -18,6 +18,15 @@ func TestEncodeDecode(t *testing.T) {
 			marshaled:   []byte{0x4, 0x0, 0x61, 0x73, 0x64, 0x66},
 		},
 		{
+			description: "[]string",
+			target:      []string{"asdf", "qwer", "zxcv"},
+			marshaled: []byte{
+				0x3, 0x0, // len(target)
+				0x4, 0x0, 0x61, 0x73, 0x64, 0x66,
+				0x4, 0x0, 0x71, 0x77, 0x65, 0x72,
+				0x4, 0x0, 0x7a, 0x78, 0x63, 0x76},
+		},
+		{
 			description: "Tversion fcall",
 			target: &Fcall{
 				Type: Tversion,
@@ -27,14 +36,43 @@ func TestEncodeDecode(t *testing.T) {
 					Version: "9PTEST",
 				},
 			},
-			marshaled: []byte{0xf, 0x0, 0x0, 0x0, 0x64, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0, 0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54},
+			marshaled: []byte{
+				0x13, 0x0, 0x0, 0x0,
+				0x64, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0,
+				0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54},
 		},
+		{
+			description: "Twalk fcall",
+			target: &Fcall{
+				Type: Twalk,
+				Tag:  5666,
+				Message: &MessageTwalk{
+					Fid:    1010,
+					Newfid: 1011,
+					Wname:  []string{"a", "b", "c"},
+				},
+			},
+			marshaled: []byte{
+				0x1a, 0x0, 0x0, 0x0,
+				0x6e, 0x22, 0x16, 0xf2, 0x3, 0x0, 0x0, 0xf3, 0x3, 0x0, 0x0,
+				0x3, 0x0, // len(wnames)
+				0x1, 0x0, 0x61, // "a"
+				0x1, 0x0, 0x62, // "b"
+				0x1, 0x0, 0x63}, // "c"
+		},
 	} {
 		t.Logf("target under test: %v", testcase.target)
 		fatalf := func(format string, args ...interface{}) {
 			t.Fatalf(testcase.description+": "+format, args...)
 		}
 
+		// check that size9p is working correctly
+		if int(size9p(testcase.target)) != len(testcase.marshaled) {
+			fatalf("size not correct: %v != %v", int(size9p(testcase.target)), len(testcase.marshaled))
+		}
+
+		t.Logf("expecting message of %v bytes", len(testcase.marshaled))
+
 		var b bytes.Buffer
 
 		enc := &encoder{&b}
@@ -58,7 +96,7 @@ func TestEncodeDecode(t *testing.T) {
 		}
 
 		if err := dec.decode(v); err != nil {
-			fatalf("error reading fcall: %v", err)
+			fatalf("error reading: %v", err)
 		}
 
 		if targetType.Kind() != reflect.Ptr {
@@ -68,5 +106,7 @@ func TestEncodeDecode(t *testing.T) {
 		if !reflect.DeepEqual(v, testcase.target) {
 			fatalf("not equal: %#v != %#v", v, testcase.target)
 		}
+		t.Logf("%#v", v)
+
 	}
 }
blob - d550f4532b8a7fa29594fd215f549c129367981e
blob + 9cb51454c9c0fd95c63d2083b8bbf90ce6cc2db5
--- fcall.go
+++ fcall.go
@@ -146,9 +146,9 @@ func newMessage(typ FcallType) (Message, error) {
 	case Rflush:
 		return nil, nil // No message body for this response.
 	case Twalk:
-
+		return &MessageTwalk{}, nil
 	case Rwalk:
-
+		return &MessageRwalk{}, nil
 	case Topen:
 
 	case Ropen:
@@ -200,6 +200,72 @@ func (mv MessageVersion) String() string {
 	return fmt.Sprintf("msize=%v version=%v", mv.MSize, mv.Version)
 }
 
+type MessageTAuth struct {
+	Afid  Fid
+	Uname string
+	Aname string
+}
+
+type MessageRAuth struct {
+	Qid Qid
+}
+
+type MessageError struct {
+	Ename string
+}
+
+type MessageTattach struct {
+	Fid   Fid
+	Afid  Fid
+	Uname string
+	Aname string
+}
+
+type MessageRattach struct {
+	Qid Qid
+}
+
+type MessageTwalk struct {
+	Fid    Fid
+	Newfid Fid
+	Wname  []string
+}
+
+func (MessageTwalk) message9p() {}
+
+type MessageRwalk struct {
+	Qid []Qid
+}
+
+func (MessageRwalk) message9p() {}
+
+type MessageTopen struct {
+	Fid  Fid
+	Mode uint8
+}
+
+type MessageRopen struct {
+	Qid   Qid
+	Msize uint32
+}
+
+type MessageTcreate struct {
+	Fid  Fid
+	Name string
+	Perm uint32
+	Mode uint8
+}
+
+type MessageTread struct {
+	Fid    Fid
+	Offset uint64
+	Count  uint32
+}
+
+type MessageRread struct {
+	Data []byte
+}
+
 // MessageFlush handles the content for the Tflush message type.
 type MessageFlush struct {
 	Oldtag Tag