14 // Codec defines the interface for encoding and decoding of 9p types.
15 // Unsupported types will throw an error.
16 type Codec interface {
17 // Unmarshal from data into the value pointed to by v.
18 Unmarshal(data []byte, v interface{}) error
20 // Marshal the value v into a byte slice.
21 Marshal(v interface{}) ([]byte, error)
23 // Size returns the encoded size for the target of v.
24 Size(v interface{}) int
27 func NewCodec() Codec {
33 func (c codec9p) Unmarshal(data []byte, v interface{}) error {
34 dec := &decoder{bytes.NewReader(data)}
38 func (c codec9p) Marshal(v interface{}) ([]byte, error) {
42 if err := enc.encode(v); err != nil {
49 func (c codec9p) Size(v interface{}) int {
53 // DecodeDir decodes a directory entry from rd using the provided codec.
54 func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
57 // pull the size off the wire
58 if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
62 p := make([]byte, ll+2)
63 binary.LittleEndian.PutUint16(p, ll) // must have size at start
65 // read out the rest of the record
66 if _, err := io.ReadFull(rd, p[2:]); err != nil {
70 return codec.Unmarshal(p, d)
73 // EncodeDir writes the directory to wr.
74 func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
75 p, err := codec.Marshal(d)
88 func (e *encoder) encode(vs ...interface{}) error {
89 for _, v := range vs {
90 switch v := v.(type) {
91 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
92 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
93 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
97 if err := e.encode(uint32(len(v))); err != nil {
101 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
106 if err := e.encode(*v); err != nil {
110 if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
114 _, err := io.WriteString(e.wr, v)
119 if err := e.encode(*v); err != nil {
124 if err := e.encode(uint16(len(v))); err != nil {
128 for _, m := range v {
129 if err := e.encode(m); err != nil {
134 if err := e.encode(*v); err != nil {
138 if err := e.encode(uint32(v.Unix())); err != nil {
142 if err := e.encode(*v); err != nil {
146 if err := e.encode(v.Type, v.Version, v.Path); err != nil {
150 if err := e.encode(*v); err != nil {
154 if err := e.encode(uint16(len(v))); err != nil {
158 elements := make([]interface{}, len(v))
163 if err := e.encode(elements...); err != nil {
167 if err := e.encode(*v); err != nil {
171 elements, err := fields9p(v)
176 if err := e.encode(uint16(size9p(elements...))); err != nil {
180 if err := e.encode(elements...); err != nil {
184 if err := e.encode(*v); err != nil {
188 if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
192 if err := e.encode(*v); err != nil {
196 elements, err := fields9p(v)
202 case MessageRstat, *MessageRstat:
203 // NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
204 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
205 // The field has been included here but we need to make sure
206 // to double emit it for Rstat.
207 if err := e.encode(uint16(size9p(elements...))); err != nil {
212 if err := e.encode(elements...); err != nil {
221 type decoder struct {
225 // read9p extracts values from rd and unmarshals them to the targets of vs.
226 func (d *decoder) decode(vs ...interface{}) error {
227 for _, v := range vs {
228 switch v := v.(type) {
229 case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
230 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
236 if err := d.decode(&ll); err != nil {
240 *v = make([]byte, int(ll))
242 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
248 // implement string[s] encoding
249 if err := d.decode(&ll); err != nil {
253 b := make([]byte, ll)
255 n, err := io.ReadFull(d.rd, b)
261 return fmt.Errorf("unexpected string length")
268 if err := d.decode(&ll); err != nil {
272 elements := make([]interface{}, int(ll))
273 *v = make([]string, int(ll))
274 for i := range elements {
275 elements[i] = &(*v)[i]
278 if err := d.decode(elements...); err != nil {
283 if err := d.decode(&epoch); err != nil {
287 *v = time.Unix(int64(epoch), 0).UTC()
289 if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
295 if err := d.decode(&ll); err != nil {
299 elements := make([]interface{}, int(ll))
300 *v = make([]Qid, int(ll))
301 for i := range elements {
302 elements[i] = &(*v)[i]
305 if err := d.decode(elements...); err != nil {
311 if err := d.decode(&ll); err != nil {
315 b := make([]byte, ll)
316 // must consume entire dir entry.
317 n, err := io.ReadFull(d.rd, b)
319 log.Println("dir readfull failed:", err, ll, n)
323 elements, err := fields9p(v)
328 dec := &decoder{bytes.NewReader(b)}
330 if err := dec.decode(elements...); err != nil {
334 if err := d.decode(&v.Type, &v.Tag); err != nil {
338 message, err := newMessage(v.Type)
343 // NOTE(stevvooe): We do a little pointer dance to allocate the
344 // new type, write to it, then assign it back to the interface as
345 // a concrete type, avoiding a pointer (the interface) to a
347 rv := reflect.New(reflect.TypeOf(message))
348 if err := d.decode(rv.Interface()); err != nil {
352 v.Message = rv.Elem().Interface().(Message)
354 elements, err := fields9p(v)
360 case *MessageRstat, MessageRstat:
361 // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
362 // in http://man.cat-v.org/plan_9/5/stat to make sense of
363 // this. The field has been included here but we need to make
364 // sure to double emit it for Rstat. decode extra size header
365 // for stat structure.
367 if err := d.decode(&ll); err != nil {
372 if err := d.decode(elements...); err != nil {
381 // size9p calculates the projected size of the values in vs when encoded into
382 // 9p binary protocol. If an element or elements are not valid for 9p encoded,
383 // the value 0 will be used for the size. The error will be detected when
385 func size9p(vs ...interface{}) uint32 {
387 for _, v := range vs {
392 switch v := v.(type) {
393 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
394 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
395 s += uint32(binary.Size(v))
397 s += uint32(binary.Size(uint32(0)) + len(v))
399 s += size9p(uint32(0), *v)
401 s += uint32(binary.Size(uint16(0)) + len(v))
405 s += size9p(uint16(0))
407 for _, sv := range v {
412 case time.Time, *time.Time:
413 // BUG(stevvooe): Y2038 is coming.
414 s += size9p(uint32(0))
416 s += size9p(v.Type, v.Version, v.Path)
420 s += size9p(uint16(0))
421 elements := make([]interface{}, len(v))
422 for i := range elements {
425 s += size9p(elements...)
430 // walk the fields of the message to get the total size. we just
431 // use the field order from the message struct. We may add tag
432 // ignoring if needed.
433 elements, err := fields9p(v)
435 // BUG(stevvooe): The options here are to return 0, panic or
436 // make this return an error. Ideally, we make it safe to
437 // return 0 and have the rest of the package do the right
438 // thing. For now, we do this, but may want to panic until
439 // things are stable.
443 s += size9p(elements...) + size9p(uint16(0))
447 s += size9p(v.Type, v.Tag, v.Message)
451 // special case twstat and rstat for size fields. See bugs in
452 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
454 case *MessageRstat, MessageRstat:
455 s += size9p(uint16(0)) // for extra size field before dir
458 // walk the fields of the message to get the total size. we just
459 // use the field order from the message struct. We may add tag
460 // ignoring if needed.
461 elements, err := fields9p(v)
463 // BUG(stevvooe): The options here are to return 0, panic or
464 // make this return an error. Ideally, we make it safe to
465 // return 0 and have the rest of the package do the right
466 // thing. For now, we do this, but may want to panic until
467 // things are stable.
471 s += size9p(elements...)
478 // fields9p lists the settable fields from a struct type for reading and
479 // writing. We are using a lot of reflection here for fairly static
480 // serialization but we can replace this in the future with generated code if
481 // performance is an issue.
482 func fields9p(v interface{}) ([]interface{}, error) {
483 rv := reflect.Indirect(reflect.ValueOf(v))
485 if rv.Kind() != reflect.Struct {
486 return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
489 var elements []interface{}
490 for i := 0; i < rv.NumField(); i++ {
493 if !f.CanInterface() {
494 // unexported field, skip it.
502 elements = append(elements, f.Interface())
508 func string9p(v interface{}) string {
513 rv := reflect.Indirect(reflect.ValueOf(v))
515 if rv.Kind() != reflect.Struct {
516 panic("not a struct")
521 for i := 0; i < rv.NumField(); i++ {
524 s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())