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 // NewCodec returns a new, standard 9P2000 codec, ready for use.
28 func NewCodec() Codec {
34 func (c codec9p) Unmarshal(data []byte, v interface{}) error {
35 dec := &decoder{bytes.NewReader(data)}
39 func (c codec9p) Marshal(v interface{}) ([]byte, error) {
43 if err := enc.encode(v); err != nil {
50 func (c codec9p) Size(v interface{}) int {
54 // DecodeDir decodes a directory entry from rd using the provided codec.
55 func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
58 // pull the size off the wire
59 if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
63 p := make([]byte, ll+2)
64 binary.LittleEndian.PutUint16(p, ll) // must have size at start
66 // read out the rest of the record
67 if _, err := io.ReadFull(rd, p[2:]); err != nil {
71 return codec.Unmarshal(p, d)
74 // EncodeDir writes the directory to wr.
75 func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
76 p, err := codec.Marshal(d)
89 func (e *encoder) encode(vs ...interface{}) error {
90 for _, v := range vs {
91 switch v := v.(type) {
92 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
93 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
94 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
98 if err := e.encode(uint32(len(v))); err != nil {
102 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
107 if err := e.encode(*v); err != nil {
111 if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
115 _, err := io.WriteString(e.wr, v)
120 if err := e.encode(*v); err != nil {
125 if err := e.encode(uint16(len(v))); err != nil {
129 for _, m := range v {
130 if err := e.encode(m); err != nil {
135 if err := e.encode(*v); err != nil {
139 if err := e.encode(uint32(v.Unix())); err != nil {
143 if err := e.encode(*v); err != nil {
147 if err := e.encode(v.Type, v.Version, v.Path); err != nil {
151 if err := e.encode(*v); err != nil {
155 if err := e.encode(uint16(len(v))); err != nil {
159 elements := make([]interface{}, len(v))
164 if err := e.encode(elements...); err != nil {
168 if err := e.encode(*v); err != nil {
172 elements, err := fields9p(v)
177 if err := e.encode(uint16(size9p(elements...))); err != nil {
181 if err := e.encode(elements...); err != nil {
185 if err := e.encode(*v); err != nil {
189 elements := make([]interface{}, len(v))
194 if err := e.encode(elements...); err != nil {
198 if err := e.encode(*v); err != nil {
202 if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
206 if err := e.encode(*v); err != nil {
210 elements, err := fields9p(v)
216 case MessageRstat, *MessageRstat:
217 // NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
218 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
219 // The field has been included here but we need to make sure
220 // to double emit it for Rstat.
221 if err := e.encode(uint16(size9p(elements...))); err != nil {
226 if err := e.encode(elements...); err != nil {
235 type decoder struct {
239 // read9p extracts values from rd and unmarshals them to the targets of vs.
240 func (d *decoder) decode(vs ...interface{}) error {
241 for _, v := range vs {
242 switch v := v.(type) {
243 case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
244 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
250 if err := d.decode(&ll); err != nil {
254 *v = make([]byte, int(ll))
256 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
262 // implement string[s] encoding
263 if err := d.decode(&ll); err != nil {
267 b := make([]byte, ll)
269 n, err := io.ReadFull(d.rd, b)
275 return fmt.Errorf("unexpected string length")
282 if err := d.decode(&ll); err != nil {
286 elements := make([]interface{}, int(ll))
287 *v = make([]string, int(ll))
288 for i := range elements {
289 elements[i] = &(*v)[i]
292 if err := d.decode(elements...); err != nil {
297 if err := d.decode(&epoch); err != nil {
301 *v = time.Unix(int64(epoch), 0).UTC()
303 if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
309 if err := d.decode(&ll); err != nil {
313 elements := make([]interface{}, int(ll))
314 *v = make([]Qid, int(ll))
315 for i := range elements {
316 elements[i] = &(*v)[i]
319 if err := d.decode(elements...); err != nil {
325 if err := d.decode(&ll); err != nil {
329 b := make([]byte, ll)
330 // must consume entire dir entry.
331 n, err := io.ReadFull(d.rd, b)
333 log.Println("dir readfull failed:", err, ll, n)
337 elements, err := fields9p(v)
342 dec := &decoder{bytes.NewReader(b)}
344 if err := dec.decode(elements...); err != nil {
351 if err := d.decode(&element); err != nil {
357 *v = append(*v, element)
360 if err := d.decode(&v.Type, &v.Tag); err != nil {
364 message, err := newMessage(v.Type)
369 // NOTE(stevvooe): We do a little pointer dance to allocate the
370 // new type, write to it, then assign it back to the interface as
371 // a concrete type, avoiding a pointer (the interface) to a
373 rv := reflect.New(reflect.TypeOf(message))
374 if err := d.decode(rv.Interface()); err != nil {
378 v.Message = rv.Elem().Interface().(Message)
380 elements, err := fields9p(v)
386 case *MessageRstat, MessageRstat:
387 // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
388 // in http://man.cat-v.org/plan_9/5/stat to make sense of
389 // this. The field has been included here but we need to make
390 // sure to double emit it for Rstat. decode extra size header
391 // for stat structure.
393 if err := d.decode(&ll); err != nil {
398 if err := d.decode(elements...); err != nil {
407 // size9p calculates the projected size of the values in vs when encoded into
408 // 9p binary protocol. If an element or elements are not valid for 9p encoded,
409 // the value 0 will be used for the size. The error will be detected when
411 func size9p(vs ...interface{}) uint32 {
413 for _, v := range vs {
418 switch v := v.(type) {
419 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
420 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
421 s += uint32(binary.Size(v))
423 s += uint32(binary.Size(uint32(0)) + len(v))
425 s += size9p(uint32(0), *v)
427 s += uint32(binary.Size(uint16(0)) + len(v))
431 s += size9p(uint16(0))
433 for _, sv := range v {
438 case time.Time, *time.Time:
439 // BUG(stevvooe): Y2038 is coming.
440 s += size9p(uint32(0))
442 s += size9p(v.Type, v.Version, v.Path)
446 s += size9p(uint16(0))
447 elements := make([]interface{}, len(v))
448 for i := range elements {
451 s += size9p(elements...)
456 // walk the fields of the message to get the total size. we just
457 // use the field order from the message struct. We may add tag
458 // ignoring if needed.
459 elements, err := fields9p(v)
461 // BUG(stevvooe): The options here are to return 0, panic or
462 // make this return an error. Ideally, we make it safe to
463 // return 0 and have the rest of the package do the right
464 // thing. For now, we do this, but may want to panic until
465 // things are stable.
469 s += size9p(elements...) + size9p(uint16(0))
473 elements := make([]interface{}, len(v))
474 for i := range elements {
477 s += size9p(elements...)
481 s += size9p(v.Type, v.Tag, v.Message)
485 // special case twstat and rstat for size fields. See bugs in
486 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
488 case *MessageRstat, MessageRstat:
489 s += size9p(uint16(0)) // for extra size field before dir
492 // walk the fields of the message to get the total size. we just
493 // use the field order from the message struct. We may add tag
494 // ignoring if needed.
495 elements, err := fields9p(v)
497 // BUG(stevvooe): The options here are to return 0, panic or
498 // make this return an error. Ideally, we make it safe to
499 // return 0 and have the rest of the package do the right
500 // thing. For now, we do this, but may want to panic until
501 // things are stable.
505 s += size9p(elements...)
512 // fields9p lists the settable fields from a struct type for reading and
513 // writing. We are using a lot of reflection here for fairly static
514 // serialization but we can replace this in the future with generated code if
515 // performance is an issue.
516 func fields9p(v interface{}) ([]interface{}, error) {
517 rv := reflect.Indirect(reflect.ValueOf(v))
519 if rv.Kind() != reflect.Struct {
520 return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
523 var elements []interface{}
524 for i := 0; i < rv.NumField(); i++ {
527 if !f.CanInterface() {
528 // unexported field, skip it.
536 elements = append(elements, f.Interface())
542 func string9p(v interface{}) string {
547 rv := reflect.Indirect(reflect.ValueOf(v))
549 if rv.Kind() != reflect.Struct {
550 panic("not a struct")
555 for i := 0; i < rv.NumField(); i++ {
558 s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())