Blob


1 package p9p
3 import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "io"
8 "reflect"
9 "strings"
10 "time"
11 )
13 // Codec defines the interface for encoding and decoding of 9p types.
14 // Unsupported types will throw an error.
15 type Codec interface {
16 // Unmarshal from data into the value pointed to by v.
17 Unmarshal(data []byte, v interface{}) error
19 // Marshal the value v into a byte slice.
20 Marshal(v interface{}) ([]byte, error)
22 // Size returns the encoded size for the target of v.
23 Size(v interface{}) int
24 }
26 // NewCodec returns a new, standard 9P2000 codec, ready for use.
27 func NewCodec() Codec {
28 return codec9p{}
29 }
31 type codec9p struct{}
33 func (c codec9p) Unmarshal(data []byte, v interface{}) error {
34 dec := &decoder{bytes.NewReader(data)}
35 return dec.decode(v)
36 }
38 func (c codec9p) Marshal(v interface{}) ([]byte, error) {
39 var b bytes.Buffer
40 enc := &encoder{&b}
42 if err := enc.encode(v); err != nil {
43 return nil, err
44 }
46 return b.Bytes(), nil
47 }
49 func (c codec9p) Size(v interface{}) int {
50 return int(size9p(v))
51 }
53 // DecodeDir decodes a directory entry from rd using the provided codec.
54 func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
55 var ll uint16
57 // pull the size off the wire
58 if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
59 return err
60 }
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 {
67 return err
68 }
70 return codec.Unmarshal(p, d)
71 }
73 // EncodeDir writes the directory to wr.
74 func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
75 p, err := codec.Marshal(d)
76 if err != nil {
77 return err
78 }
80 _, err = wr.Write(p)
81 return err
82 }
84 type encoder struct {
85 wr io.Writer
86 }
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 {
94 return err
95 }
96 case []byte:
97 if err := e.encode(uint32(len(v))); err != nil {
98 return err
99 }
101 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
102 return err
105 case *[]byte:
106 if err := e.encode(*v); err != nil {
107 return err
109 case string:
110 if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
111 return err
114 _, err := io.WriteString(e.wr, v)
115 if err != nil {
116 return err
118 case *string:
119 if err := e.encode(*v); err != nil {
120 return err
123 case []string:
124 if err := e.encode(uint16(len(v))); err != nil {
125 return err
128 for _, m := range v {
129 if err := e.encode(m); err != nil {
130 return err
133 case *[]string:
134 if err := e.encode(*v); err != nil {
135 return err
137 case time.Time:
138 if err := e.encode(uint32(v.Unix())); err != nil {
139 return err
141 case *time.Time:
142 if err := e.encode(*v); err != nil {
143 return err
145 case Qid:
146 if err := e.encode(v.Type, v.Version, v.Path); err != nil {
147 return err
149 case *Qid:
150 if err := e.encode(*v); err != nil {
151 return err
153 case []Qid:
154 if err := e.encode(uint16(len(v))); err != nil {
155 return err
158 elements := make([]interface{}, len(v))
159 for i := range v {
160 elements[i] = &v[i]
163 if err := e.encode(elements...); err != nil {
164 return err
166 case *[]Qid:
167 if err := e.encode(*v); err != nil {
168 return err
170 case Dir:
171 elements, err := fields9p(v)
172 if err != nil {
173 return err
176 if err := e.encode(uint16(size9p(elements...))); err != nil {
177 return err
180 if err := e.encode(elements...); err != nil {
181 return err
183 case *Dir:
184 if err := e.encode(*v); err != nil {
185 return err
187 case []Dir:
188 elements := make([]interface{}, len(v))
189 for i := range v {
190 elements[i] = &v[i]
193 if err := e.encode(elements...); err != nil {
194 return err
196 case *[]Dir:
197 if err := e.encode(*v); err != nil {
198 return err
200 case Fcall:
201 if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
202 return err
204 case *Fcall:
205 if err := e.encode(*v); err != nil {
206 return err
208 case Message:
209 elements, err := fields9p(v)
210 if err != nil {
211 return err
214 switch v.(type) {
215 case MessageRstat, *MessageRstat:
216 // NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
217 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
218 // The field has been included here but we need to make sure
219 // to double emit it for Rstat.
220 if err := e.encode(uint16(size9p(elements...))); err != nil {
221 return err
225 if err := e.encode(elements...); err != nil {
226 return err
231 return nil
234 type decoder struct {
235 rd io.Reader
238 // read9p extracts values from rd and unmarshals them to the targets of vs.
239 func (d *decoder) decode(vs ...interface{}) error {
240 for _, v := range vs {
241 switch v := v.(type) {
242 case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
243 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
244 return err
246 case *[]byte:
247 var ll uint32
249 if err := d.decode(&ll); err != nil {
250 return err
253 if ll > 0 {
254 *v = make([]byte, int(ll))
257 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
258 return err
260 case *string:
261 var ll uint16
263 // implement string[s] encoding
264 if err := d.decode(&ll); err != nil {
265 return err
268 b := make([]byte, ll)
270 n, err := io.ReadFull(d.rd, b)
271 if err != nil {
272 return err
275 if n != int(ll) {
276 return fmt.Errorf("unexpected string length")
279 *v = string(b)
280 case *[]string:
281 var ll uint16
283 if err := d.decode(&ll); err != nil {
284 return err
287 elements := make([]interface{}, int(ll))
288 *v = make([]string, int(ll))
289 for i := range elements {
290 elements[i] = &(*v)[i]
293 if err := d.decode(elements...); err != nil {
294 return err
296 case *time.Time:
297 var epoch uint32
298 if err := d.decode(&epoch); err != nil {
299 return err
302 *v = time.Unix(int64(epoch), 0).UTC()
303 case *Qid:
304 if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
305 return err
307 case *[]Qid:
308 var ll uint16
310 if err := d.decode(&ll); err != nil {
311 return err
314 elements := make([]interface{}, int(ll))
315 *v = make([]Qid, int(ll))
316 for i := range elements {
317 elements[i] = &(*v)[i]
320 if err := d.decode(elements...); err != nil {
321 return err
323 case *Dir:
324 var ll uint16
326 if err := d.decode(&ll); err != nil {
327 return err
330 b := make([]byte, ll)
331 // must consume entire dir entry.
332 if _, err := io.ReadFull(d.rd, b); err != nil {
333 return err
336 elements, err := fields9p(v)
337 if err != nil {
338 return err
341 dec := &decoder{bytes.NewReader(b)}
343 if err := dec.decode(elements...); err != nil {
344 return err
346 case *[]Dir:
347 *v = make([]Dir, 0)
348 for {
349 element := Dir{}
350 if err := d.decode(&element); err != nil {
351 if err == io.EOF {
352 return nil
354 return err
356 *v = append(*v, element)
358 case *Fcall:
359 if err := d.decode(&v.Type, &v.Tag); err != nil {
360 return err
363 message, err := newMessage(v.Type)
364 if err != nil {
365 return err
368 // NOTE(stevvooe): We do a little pointer dance to allocate the
369 // new type, write to it, then assign it back to the interface as
370 // a concrete type, avoiding a pointer (the interface) to a
371 // pointer.
372 rv := reflect.New(reflect.TypeOf(message))
373 if err := d.decode(rv.Interface()); err != nil {
374 return err
377 v.Message = rv.Elem().Interface().(Message)
378 case Message:
379 elements, err := fields9p(v)
380 if err != nil {
381 return err
384 switch v.(type) {
385 case *MessageRstat, MessageRstat:
386 // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
387 // in http://man.cat-v.org/plan_9/5/stat to make sense of
388 // this. The field has been included here but we need to make
389 // sure to double emit it for Rstat. decode extra size header
390 // for stat structure.
391 var ll uint16
392 if err := d.decode(&ll); err != nil {
393 return err
397 if err := d.decode(elements...); err != nil {
398 return err
403 return nil
406 // size9p calculates the projected size of the values in vs when encoded into
407 // 9p binary protocol. If an element or elements are not valid for 9p encoded,
408 // the value 0 will be used for the size. The error will be detected when
409 // encoding.
410 func size9p(vs ...interface{}) uint32 {
411 var s uint32
412 for _, v := range vs {
413 if v == nil {
414 continue
417 switch v := v.(type) {
418 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
419 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
420 s += uint32(binary.Size(v))
421 case []byte:
422 s += uint32(binary.Size(uint32(0)) + len(v))
423 case *[]byte:
424 s += size9p(uint32(0), *v)
425 case string:
426 s += uint32(binary.Size(uint16(0)) + len(v))
427 case *string:
428 s += size9p(*v)
429 case []string:
430 s += size9p(uint16(0))
432 for _, sv := range v {
433 s += size9p(sv)
435 case *[]string:
436 s += size9p(*v)
437 case time.Time, *time.Time:
438 // BUG(stevvooe): Y2038 is coming.
439 s += size9p(uint32(0))
440 case Qid:
441 s += size9p(v.Type, v.Version, v.Path)
442 case *Qid:
443 s += size9p(*v)
444 case []Qid:
445 s += size9p(uint16(0))
446 elements := make([]interface{}, len(v))
447 for i := range elements {
448 elements[i] = &v[i]
450 s += size9p(elements...)
451 case *[]Qid:
452 s += size9p(*v)
454 case Dir:
455 // walk the fields of the message to get the total size. we just
456 // use the field order from the message struct. We may add tag
457 // ignoring if needed.
458 elements, err := fields9p(v)
459 if err != nil {
460 // BUG(stevvooe): The options here are to return 0, panic or
461 // make this return an error. Ideally, we make it safe to
462 // return 0 and have the rest of the package do the right
463 // thing. For now, we do this, but may want to panic until
464 // things are stable.
465 panic(err)
468 s += size9p(elements...) + size9p(uint16(0))
469 case *Dir:
470 s += size9p(*v)
471 case []Dir:
472 elements := make([]interface{}, len(v))
473 for i := range elements {
474 elements[i] = &v[i]
476 s += size9p(elements...)
477 case *[]Dir:
478 s += size9p(*v)
479 case Fcall:
480 s += size9p(v.Type, v.Tag, v.Message)
481 case *Fcall:
482 s += size9p(*v)
483 case Message:
484 // special case twstat and rstat for size fields. See bugs in
485 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
486 switch v.(type) {
487 case *MessageRstat, MessageRstat:
488 s += size9p(uint16(0)) // for extra size field before dir
491 // walk the fields of the message to get the total size. we just
492 // use the field order from the message struct. We may add tag
493 // ignoring if needed.
494 elements, err := fields9p(v)
495 if err != nil {
496 // BUG(stevvooe): The options here are to return 0, panic or
497 // make this return an error. Ideally, we make it safe to
498 // return 0 and have the rest of the package do the right
499 // thing. For now, we do this, but may want to panic until
500 // things are stable.
501 panic(err)
504 s += size9p(elements...)
508 return s
511 // fields9p lists the settable fields from a struct type for reading and
512 // writing. We are using a lot of reflection here for fairly static
513 // serialization but we can replace this in the future with generated code if
514 // performance is an issue.
515 func fields9p(v interface{}) ([]interface{}, error) {
516 rv := reflect.Indirect(reflect.ValueOf(v))
518 if rv.Kind() != reflect.Struct {
519 return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
522 var elements []interface{}
523 for i := 0; i < rv.NumField(); i++ {
524 f := rv.Field(i)
526 if !f.CanInterface() {
527 // unexported field, skip it.
528 continue
531 if f.CanAddr() {
532 f = f.Addr()
535 elements = append(elements, f.Interface())
538 return elements, nil
541 func string9p(v interface{}) string {
542 if v == nil {
543 return "nil"
546 rv := reflect.Indirect(reflect.ValueOf(v))
548 if rv.Kind() != reflect.Struct {
549 panic("not a struct")
552 var s string
554 for i := 0; i < rv.NumField(); i++ {
555 f := rv.Field(i)
557 s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())
560 return s