Commit Diff


commit - e9f5e41480fec822e81050643644fd58a98ac861
commit + d6198009fad10d2c6e0819feb0fa20608628dbcf
blob - f1889d8ce531e8e636d504b713ea89ca3146a979
blob + a984f15e43f90d71c7c82e281df8cf2cbeb640ee
--- encoding.go
+++ encoding.go
@@ -4,7 +4,9 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+	"log"
 	"reflect"
+	"time"
 )
 
 // NOTE(stevvooe): This file covers 9p encoding and decoding (despite just
@@ -34,6 +36,14 @@ func (e *encoder) encode(vs ...interface{}) error {
 			if err := e.encode(elements...); err != nil {
 				return err
 			}
+		case *[]byte:
+			if err := e.encode(uint16(len(*v))); err != nil {
+				return err
+			}
+
+			if err := e.encode(*v); err != nil {
+				return err
+			}
 		case *string:
 			if err := e.encode(*v); err != nil {
 				return err
@@ -48,10 +58,7 @@ func (e *encoder) encode(vs ...interface{}) error {
 			if err != nil {
 				return err
 			}
-		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
-			// ignoring if needed.
+		case Message, *Qid, *Dir:
 			elements, err := fields9p(v)
 			if err != nil {
 				return err
@@ -60,6 +67,31 @@ func (e *encoder) encode(vs ...interface{}) error {
 			if err := e.encode(elements...); err != nil {
 				return err
 			}
+		case *[]Qid:
+			if err := e.encode(*v); err != nil {
+				return err
+			}
+		case []Qid:
+			if err := e.encode(uint16(len(v))); err != nil {
+				return err
+			}
+
+			elements := make([]interface{}, len(v))
+			for i := range v {
+				elements[i] = &v[i]
+			}
+
+			if err := e.encode(elements...); err != nil {
+				return err
+			}
+		case time.Time:
+			if err := e.encode(uint32(v.Unix())); err != nil {
+				return err
+			}
+		case *time.Time:
+			if err := e.encode(*v); err != nil {
+				return err
+			}
 		case Fcall:
 			if err := e.encode(&v); err != nil {
 				return err
@@ -85,6 +117,7 @@ type decoder struct {
 // read9p extracts values from rd and unmarshals them to the targets of vs.
 func (d *decoder) decode(vs ...interface{}) error {
 	for _, v := range vs {
+		before := fmt.Sprintf("%#v", v)
 		switch v := v.(type) {
 		case *string:
 			var ll uint16
@@ -120,6 +153,18 @@ func (d *decoder) decode(vs ...interface{}) error {
 			}
 
 			if err := d.decode(elements...); err != nil {
+				return err
+			}
+		case *[]byte:
+			var ll uint16
+
+			if err := d.decode(&ll); err != nil {
+				return err
+			}
+
+			*v = make([]byte, int(ll))
+
+			if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
 				return err
 			}
 		case *Fcall:
@@ -137,7 +182,30 @@ func (d *decoder) decode(vs ...interface{}) error {
 			if err := d.decode(v.Message); err != nil {
 				return err
 			}
-		case Message:
+		case *[]Qid:
+			var ll uint16
+
+			if err := d.decode(&ll); err != nil {
+				return err
+			}
+
+			elements := make([]interface{}, int(ll))
+			*v = make([]Qid, int(ll))
+			for i := range elements {
+				elements[i] = &(*v)[i]
+			}
+
+			if err := d.decode(elements...); err != nil {
+				return err
+			}
+		case *time.Time:
+			var epoch uint32
+			if err := d.decode(&epoch); err != nil {
+				return err
+			}
+
+			*v = time.Unix(int64(epoch), 0).UTC()
+		case Message, *Qid, *Dir:
 			elements, err := fields9p(v)
 			if err != nil {
 				return err
@@ -151,6 +219,7 @@ func (d *decoder) decode(vs ...interface{}) error {
 				return err
 			}
 		}
+		log.Printf("Decode: %v -> %#v", before, v)
 	}
 
 	return nil
@@ -182,7 +251,20 @@ func size9p(vs ...interface{}) uint32 {
 			}
 
 			s += size9p(elements...)
-		case Message:
+		case *[]byte:
+			s += size9p(uint16(0), *v)
+		case *[]Qid:
+			s += size9p(*v)
+		case []Qid:
+			s += size9p(uint16(0))
+			elements := make([]interface{}, len(v))
+			for i := range elements {
+				elements[i] = &v[i]
+			}
+			s += size9p(elements...)
+		case time.Time, *time.Time:
+			s += size9p(uint32(0))
+		case Message, *Qid, *Dir:
 			// 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
 			// ignoring if needed.
@@ -217,6 +299,7 @@ func fields9p(v interface{}) ([]interface{}, error) {
 	rv := reflect.Indirect(reflect.ValueOf(v))
 
 	if rv.Kind() != reflect.Struct {
+		panic("asdf")
 		return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
 	}
 
@@ -229,6 +312,7 @@ func fields9p(v interface{}) ([]interface{}, error) {
 		}
 
 		if !f.CanSet() {
+			panic("asdf")
 			return nil, fmt.Errorf("cannot set %v", f)
 		}
 
blob - fb38ea4090dfd47997571c4808dcd1bf418408b6
blob + 9a676b70dc7a2076e7b7b306bda3332a1794a936
--- encoding_test.go
+++ encoding_test.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"reflect"
 	"testing"
+	"time"
 )
 
 func TestEncodeDecode(t *testing.T) {
@@ -60,17 +61,93 @@ func TestEncodeDecode(t *testing.T) {
 				0x1, 0x0, 0x62, // "b"
 				0x1, 0x0, 0x63}, // "c"
 		},
+		{
+			description: "Rwalk call",
+			target: &Fcall{
+				Type: Rwalk,
+				Tag:  5556,
+				Message: &MessageRwalk{
+					Qids: []Qid{
+						Qid{
+							Type:    QTDIR,
+							Path:    1111,
+							Version: 11112,
+						},
+						Qid{Type: QTFILE,
+							Version: 1112,
+							Path:    11114},
+					},
+				},
+			},
+			marshaled: []byte{
+				0x23, 0x0, 0x0, 0x0,
+				0x6f, 0xb4, 0x15,
+				0x2, 0x0,
+				0x80, 0x68, 0x2b, 0x0, 0x0, 0x57, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+				0x0, 0x58, 0x4, 0x0, 0x0, 0x6a, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			description: "Rread fcall",
+			target: &Fcall{
+				Type: Rread,
+				Tag:  5556,
+				Message: &MessageRread{
+					Data: []byte("a lot of byte data"),
+				},
+			},
+			marshaled: []byte{
+				0x1b, 0x0, 0x0, 0x0,
+				0x75, 0xb4, 0x15,
+				0x12, 0x0,
+				0x61, 0x20, 0x6c, 0x6f, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61},
+		},
+		{
+			description: "",
+			target: &Fcall{
+				Type: Rstat,
+				Tag:  5556,
+				Message: &MessageRstat{
+					Stat: Dir{
+						Type: ^uint16(0),
+						Dev:  ^uint32(0),
+						Qid: Qid{
+							Type:    QTDIR,
+							Version: ^uint32(0),
+							Path:    ^uint64(0),
+						},
+						Mode:       DMDIR | DMREAD,
+						AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
+						ModTime:    time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
+						Length:     ^uint64(0),
+						Name:       "somedir",
+						UID:        "uid",
+						GID:        "gid",
+						MUID:       "muid",
+					},
+				},
+			},
+			marshaled: []byte{
+				0x47, 0x0, 0x0, 0x0,
+				0x7d, 0xb4, 0x15,
+				0xff, 0xff, // type
+				0xff, 0xff, 0xff, 0xff, // dev
+				0x80, 0xff, 0xff, 0xff, 0xff, // qid.type, qid.version
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
+				0x4, 0x0, 0x0, 0x80, // mode
+				0x25, 0x98, 0xb8, 0x43, // atime
+				0x25, 0x98, 0xb8, 0x43, // mtime
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // length
+				0x7, 0x0, 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x69, 0x72,
+				0x3, 0x0, 0x75, 0x69, 0x64, // uid
+				0x3, 0x0, 0x67, 0x69, 0x64, // gid
+				0x4, 0x0, 0x6d, 0x75, 0x69, 0x64}, // muid
+		},
 	} {
 		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
@@ -83,9 +160,14 @@ func TestEncodeDecode(t *testing.T) {
 		}
 
 		if !bytes.Equal(b.Bytes(), testcase.marshaled) {
-			fatalf("unexpected bytes for fcall: %#v != %#v", b.Bytes(), testcase.marshaled)
+			fatalf("unexpected bytes for fcall: \n%#v != \n%#v", b.Bytes(), testcase.marshaled)
 		}
 
+		// 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))
+		}
+
 		var v interface{}
 		targetType := reflect.TypeOf(testcase.target)
 
@@ -104,8 +186,9 @@ func TestEncodeDecode(t *testing.T) {
 		}
 
 		if !reflect.DeepEqual(v, testcase.target) {
-			fatalf("not equal: %#v != %#v", v, testcase.target)
+			fatalf("not equal: %v != %v", v, testcase.target)
 		}
+
 		t.Logf("%#v", v)
 
 	}
blob - 9cb51454c9c0fd95c63d2083b8bbf90ce6cc2db5
blob + 6dfb0d4b0a2d2b11bb9074dafa15a299b06f0777
--- fcall.go
+++ fcall.go
@@ -142,7 +142,7 @@ func newMessage(typ FcallType) (Message, error) {
 	case Rerror:
 
 	case Tflush:
-		return &MessageFlush{}, nil
+		return &MessageTflush{}, nil
 	case Rflush:
 		return nil, nil // No message body for this response.
 	case Twalk:
@@ -160,7 +160,7 @@ func newMessage(typ FcallType) (Message, error) {
 	case Tread:
 
 	case Rread:
-
+		return &MessageRread{}, nil
 	case Twrite:
 
 	case Rwrite:
@@ -176,7 +176,7 @@ func newMessage(typ FcallType) (Message, error) {
 	case Tstat:
 
 	case Rstat:
-
+		return &MessageRstat{}, nil
 	case Twstat:
 
 	case Rwstat:
@@ -196,6 +196,7 @@ type MessageVersion struct {
 }
 
 func (MessageVersion) message9p() {}
+
 func (mv MessageVersion) String() string {
 	return fmt.Sprintf("msize=%v version=%v", mv.MSize, mv.Version)
 }
@@ -210,10 +211,17 @@ type MessageRAuth struct {
 	Qid Qid
 }
 
-type MessageError struct {
+type MessageRerror struct {
 	Ename string
 }
 
+// MessageTflush handles the content for the Tflush message type.
+type MessageTflush struct {
+	Oldtag Tag
+}
+
+func (MessageTflush) message9p() {}
+
 type MessageTattach struct {
 	Fid   Fid
 	Afid  Fid
@@ -234,7 +242,7 @@ type MessageTwalk struct {
 func (MessageTwalk) message9p() {}
 
 type MessageRwalk struct {
-	Qid []Qid
+	Qids []Qid
 }
 
 func (MessageRwalk) message9p() {}
@@ -244,11 +252,15 @@ type MessageTopen struct {
 	Mode uint8
 }
 
+func (MessageTopen) message9p() {}
+
 type MessageRopen struct {
 	Qid   Qid
 	Msize uint32
 }
 
+func (MessageRopen) message9p() {}
+
 type MessageTcreate struct {
 	Fid  Fid
 	Name string
@@ -256,19 +268,62 @@ type MessageTcreate struct {
 	Mode uint8
 }
 
+func (MessageTcreate) message9p() {}
+
+type MessageRcreate struct {
+	Qid    Qid
+	IOUnit uint32
+}
+
+func (MessageRcreate) message9p() {}
+
 type MessageTread struct {
 	Fid    Fid
 	Offset uint64
 	Count  uint32
 }
 
+func (MessageTread) message9p() {}
+
 type MessageRread struct {
 	Data []byte
 }
 
-// MessageFlush handles the content for the Tflush message type.
-type MessageFlush struct {
-	Oldtag Tag
+func (MessageRread) message9p() {}
+
+type MessageTwrite struct {
+	Fid    Fid
+	Offset uint64
+	Data   []byte
 }
 
-func (MessageFlush) message9p() {}
+func (MessageTwrite) message9p() {}
+
+type MessageRwrite struct {
+	Count uint32
+}
+
+func (MessageRwrite) message9p() {}
+
+type MessageTclunk struct {
+	Fid Fid
+}
+
+type MessageTremove struct {
+	Fid Fid
+}
+
+type MessageTstat struct {
+	Fid Fid
+}
+
+type MessageRstat struct {
+	Stat Dir
+}
+
+func (MessageRstat) message9p() {}
+
+type MessageTwstat struct {
+	Fid  Fid
+	Stat Dir
+}
blob - 524e7b4ec21e4fcfb010d59e7ba62e07fb3a78f1
blob + a721ab636b2e82ae5b06a92c70f3c5b17e96a47e
--- types.go
+++ types.go
@@ -8,26 +8,26 @@ const (
 )
 
 const (
-	DMDIR    = 0x80000000 /* mode bit for directories */
-	DMAPPEND = 0x40000000 /* mode bit for append only files */
-	DMEXCL   = 0x20000000 /* mode bit for exclusive use files */
-	DMMOUNT  = 0x10000000 /* mode bit for mounted channel */
-	DMAUTH   = 0x08000000 /* mode bit for authentication file */
-	DMTMP    = 0x04000000 /* mode bit for non-backed-up files */
-	DMREAD   = 0x4        /* mode bit for read permission */
-	DMWRITE  = 0x2        /* mode bit for write permission */
-	DMEXEC   = 0x1        /* mode bit for execute permission */
+	DMDIR    = 0x80000000 // mode bit for directories
+	DMAPPEND = 0x40000000 // mode bit for append only files
+	DMEXCL   = 0x20000000 // mode bit for exclusive use files
+	DMMOUNT  = 0x10000000 // mode bit for mounted channel
+	DMAUTH   = 0x08000000 // mode bit for authentication file
+	DMTMP    = 0x04000000 // mode bit for non-backed-up files
+	DMREAD   = 0x4        // mode bit for read permission
+	DMWRITE  = 0x2        // mode bit for write permission
+	DMEXEC   = 0x1        // mode bit for execute permission
 )
 
 const (
-	OREAD   = 0      /* open for read */
-	OWRITE  = 1      /* write */
-	ORDWR   = 2      /* read and write */
-	OEXEC   = 3      /* execute, == read but check execute permission */
-	OTRUNC  = 16     /* or'ed in (except for exec), truncate file first */
-	OCEXEC  = 32     /* or'ed in, close on exec */
-	ORCLOSE = 64     /* or'ed in, remove on close */
-	OEXCL   = 0x1000 /* or'ed in, exclusive use (create only) */
+	OREAD   = 0      // open for read
+	OWRITE  = 1      // write
+	ORDWR   = 2      // read and write
+	OEXEC   = 3      // execute, == read but check execute permission
+	OTRUNC  = 16     // or'ed in (except for exec), truncate file first
+	OCEXEC  = 32     // or'ed in, close on exec
+	ORCLOSE = 64     // or'ed in, remove on close
+	OEXCL   = 0x1000 // or'ed in, exclusive use (create only)
 )
 
 type QType uint8
@@ -39,7 +39,7 @@ const (
 	QTMOUNT  QType = 0x10 // type bit for mounted channel
 	QTAUTH   QType = 0x08 // type bit for authentication file
 	QTTMP    QType = 0x04 // type bit for not-backed-up file
-	QTFILE   QType = 0x00 // plain file */
+	QTFILE   QType = 0x00 // plain file
 )
 
 type Fid uint32
@@ -51,21 +51,18 @@ type Qid struct {
 }
 
 type Dir struct {
-	Type   uint16
-	Dev    uint32
-	Qid    Qid
-	Mode   uint32
-	Length uint64
-	Name   string
+	Type       uint16
+	Dev        uint32
+	Qid        Qid
+	Mode       uint32
+	AccessTime time.Time
+	ModTime    time.Time
+	Length     uint64
+	Name       string
+	UID        string
+	GID        string
+	MUID       string
 
-	AccessTime       time.Time // TODO(stevvooe): Need special serialization type.
-	ModificationTime time.Time
-
-	/* Not really used for our implementation */
-	UID  string
-	GID  string
-	MUID string
-
 	// TODO(stevvooe): 9p2000.u/L should go here.
 }