Blob


1 package p9p
3 import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "io"
8 "log"
9 "reflect"
10 "strings"
11 "time"
12 )
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
25 }
27 // NewCodec returns a new, standard 9P2000 codec, ready for use.
28 func NewCodec() Codec {
29 return codec9p{}
30 }
32 type codec9p struct{}
34 func (c codec9p) Unmarshal(data []byte, v interface{}) error {
35 dec := &decoder{bytes.NewReader(data)}
36 return dec.decode(v)
37 }
39 func (c codec9p) Marshal(v interface{}) ([]byte, error) {
40 var b bytes.Buffer
41 enc := &encoder{&b}
43 if err := enc.encode(v); err != nil {
44 return nil, err
45 }
47 return b.Bytes(), nil
48 }
50 func (c codec9p) Size(v interface{}) int {
51 return int(size9p(v))
52 }
54 // DecodeDir decodes a directory entry from rd using the provided codec.
55 func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
56 var ll uint16
58 // pull the size off the wire
59 if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
60 return err
61 }
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 {
68 return err
69 }
71 return codec.Unmarshal(p, d)
72 }
74 // EncodeDir writes the directory to wr.
75 func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
76 p, err := codec.Marshal(d)
77 if err != nil {
78 return err
79 }
81 _, err = wr.Write(p)
82 return err
83 }
85 type encoder struct {
86 wr io.Writer
87 }
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 {
95 return err
96 }
97 case []byte:
98 if err := e.encode(uint32(len(v))); err != nil {
99 return err
102 if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
103 return err
106 case *[]byte:
107 if err := e.encode(*v); err != nil {
108 return err
110 case string:
111 if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
112 return err
115 _, err := io.WriteString(e.wr, v)
116 if err != nil {
117 return err
119 case *string:
120 if err := e.encode(*v); err != nil {
121 return err
124 case []string:
125 if err := e.encode(uint16(len(v))); err != nil {
126 return err
129 for _, m := range v {
130 if err := e.encode(m); err != nil {
131 return err
134 case *[]string:
135 if err := e.encode(*v); err != nil {
136 return err
138 case time.Time:
139 if err := e.encode(uint32(v.Unix())); err != nil {
140 return err
142 case *time.Time:
143 if err := e.encode(*v); err != nil {
144 return err
146 case Qid:
147 if err := e.encode(v.Type, v.Version, v.Path); err != nil {
148 return err
150 case *Qid:
151 if err := e.encode(*v); err != nil {
152 return err
154 case []Qid:
155 if err := e.encode(uint16(len(v))); err != nil {
156 return err
159 elements := make([]interface{}, len(v))
160 for i := range v {
161 elements[i] = &v[i]
164 if err := e.encode(elements...); err != nil {
165 return err
167 case *[]Qid:
168 if err := e.encode(*v); err != nil {
169 return err
171 case Dir:
172 elements, err := fields9p(v)
173 if err != nil {
174 return err
177 if err := e.encode(uint16(size9p(elements...))); err != nil {
178 return err
181 if err := e.encode(elements...); err != nil {
182 return err
184 case *Dir:
185 if err := e.encode(*v); err != nil {
186 return err
188 case []Dir:
189 elements := make([]interface{}, len(v))
190 for i := range v {
191 elements[i] = &v[i]
194 if err := e.encode(elements...); err != nil {
195 return err
197 case *[]Dir:
198 if err := e.encode(*v); err != nil {
199 return err
201 case Fcall:
202 if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
203 return err
205 case *Fcall:
206 if err := e.encode(*v); err != nil {
207 return err
209 case Message:
210 elements, err := fields9p(v)
211 if err != nil {
212 return err
215 switch v.(type) {
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 {
222 return err
226 if err := e.encode(elements...); err != nil {
227 return err
232 return nil
235 type decoder struct {
236 rd io.Reader
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 {
245 return err
247 case *[]byte:
248 var ll uint32
250 if err := d.decode(&ll); err != nil {
251 return err
254 if ll > 0 {
255 *v = make([]byte, int(ll))
258 if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
259 return err
261 case *string:
262 var ll uint16
264 // implement string[s] encoding
265 if err := d.decode(&ll); err != nil {
266 return err
269 b := make([]byte, ll)
271 n, err := io.ReadFull(d.rd, b)
272 if err != nil {
273 return err
276 if n != int(ll) {
277 return fmt.Errorf("unexpected string length")
280 *v = string(b)
281 case *[]string:
282 var ll uint16
284 if err := d.decode(&ll); err != nil {
285 return err
288 elements := make([]interface{}, int(ll))
289 *v = make([]string, int(ll))
290 for i := range elements {
291 elements[i] = &(*v)[i]
294 if err := d.decode(elements...); err != nil {
295 return err
297 case *time.Time:
298 var epoch uint32
299 if err := d.decode(&epoch); err != nil {
300 return err
303 *v = time.Unix(int64(epoch), 0).UTC()
304 case *Qid:
305 if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
306 return err
308 case *[]Qid:
309 var ll uint16
311 if err := d.decode(&ll); err != nil {
312 return err
315 elements := make([]interface{}, int(ll))
316 *v = make([]Qid, int(ll))
317 for i := range elements {
318 elements[i] = &(*v)[i]
321 if err := d.decode(elements...); err != nil {
322 return err
324 case *Dir:
325 var ll uint16
327 if err := d.decode(&ll); err != nil {
328 return err
331 b := make([]byte, ll)
332 // must consume entire dir entry.
333 n, err := io.ReadFull(d.rd, b)
334 if err != nil {
335 log.Println("dir readfull failed:", err, ll, n)
336 return err
339 elements, err := fields9p(v)
340 if err != nil {
341 return err
344 dec := &decoder{bytes.NewReader(b)}
346 if err := dec.decode(elements...); err != nil {
347 return err
349 case *[]Dir:
350 *v = make([]Dir, 0)
351 for {
352 element := Dir{}
353 if err := d.decode(&element); err != nil {
354 if err == io.EOF {
355 return nil
357 return err
359 *v = append(*v, element)
361 case *Fcall:
362 if err := d.decode(&v.Type, &v.Tag); err != nil {
363 return err
366 message, err := newMessage(v.Type)
367 if err != nil {
368 return err
371 // NOTE(stevvooe): We do a little pointer dance to allocate the
372 // new type, write to it, then assign it back to the interface as
373 // a concrete type, avoiding a pointer (the interface) to a
374 // pointer.
375 rv := reflect.New(reflect.TypeOf(message))
376 if err := d.decode(rv.Interface()); err != nil {
377 return err
380 v.Message = rv.Elem().Interface().(Message)
381 case Message:
382 elements, err := fields9p(v)
383 if err != nil {
384 return err
387 switch v.(type) {
388 case *MessageRstat, MessageRstat:
389 // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
390 // in http://man.cat-v.org/plan_9/5/stat to make sense of
391 // this. The field has been included here but we need to make
392 // sure to double emit it for Rstat. decode extra size header
393 // for stat structure.
394 var ll uint16
395 if err := d.decode(&ll); err != nil {
396 return err
400 if err := d.decode(elements...); err != nil {
401 return err
406 return nil
409 // size9p calculates the projected size of the values in vs when encoded into
410 // 9p binary protocol. If an element or elements are not valid for 9p encoded,
411 // the value 0 will be used for the size. The error will be detected when
412 // encoding.
413 func size9p(vs ...interface{}) uint32 {
414 var s uint32
415 for _, v := range vs {
416 if v == nil {
417 continue
420 switch v := v.(type) {
421 case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
422 *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
423 s += uint32(binary.Size(v))
424 case []byte:
425 s += uint32(binary.Size(uint32(0)) + len(v))
426 case *[]byte:
427 s += size9p(uint32(0), *v)
428 case string:
429 s += uint32(binary.Size(uint16(0)) + len(v))
430 case *string:
431 s += size9p(*v)
432 case []string:
433 s += size9p(uint16(0))
435 for _, sv := range v {
436 s += size9p(sv)
438 case *[]string:
439 s += size9p(*v)
440 case time.Time, *time.Time:
441 // BUG(stevvooe): Y2038 is coming.
442 s += size9p(uint32(0))
443 case Qid:
444 s += size9p(v.Type, v.Version, v.Path)
445 case *Qid:
446 s += size9p(*v)
447 case []Qid:
448 s += size9p(uint16(0))
449 elements := make([]interface{}, len(v))
450 for i := range elements {
451 elements[i] = &v[i]
453 s += size9p(elements...)
454 case *[]Qid:
455 s += size9p(*v)
457 case 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)
462 if err != nil {
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.
468 panic(err)
471 s += size9p(elements...) + size9p(uint16(0))
472 case *Dir:
473 s += size9p(*v)
474 case []Dir:
475 elements := make([]interface{}, len(v))
476 for i := range elements {
477 elements[i] = &v[i]
479 s += size9p(elements...)
480 case *[]Dir:
481 s += size9p(*v)
482 case Fcall:
483 s += size9p(v.Type, v.Tag, v.Message)
484 case *Fcall:
485 s += size9p(*v)
486 case Message:
487 // special case twstat and rstat for size fields. See bugs in
488 // http://man.cat-v.org/plan_9/5/stat to make sense of this.
489 switch v.(type) {
490 case *MessageRstat, MessageRstat:
491 s += size9p(uint16(0)) // for extra size field before dir
494 // walk the fields of the message to get the total size. we just
495 // use the field order from the message struct. We may add tag
496 // ignoring if needed.
497 elements, err := fields9p(v)
498 if err != nil {
499 // BUG(stevvooe): The options here are to return 0, panic or
500 // make this return an error. Ideally, we make it safe to
501 // return 0 and have the rest of the package do the right
502 // thing. For now, we do this, but may want to panic until
503 // things are stable.
504 panic(err)
507 s += size9p(elements...)
511 return s
514 // fields9p lists the settable fields from a struct type for reading and
515 // writing. We are using a lot of reflection here for fairly static
516 // serialization but we can replace this in the future with generated code if
517 // performance is an issue.
518 func fields9p(v interface{}) ([]interface{}, error) {
519 rv := reflect.Indirect(reflect.ValueOf(v))
521 if rv.Kind() != reflect.Struct {
522 return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
525 var elements []interface{}
526 for i := 0; i < rv.NumField(); i++ {
527 f := rv.Field(i)
529 if !f.CanInterface() {
530 // unexported field, skip it.
531 continue
534 if f.CanAddr() {
535 f = f.Addr()
538 elements = append(elements, f.Interface())
541 return elements, nil
544 func string9p(v interface{}) string {
545 if v == nil {
546 return "nil"
549 rv := reflect.Indirect(reflect.ValueOf(v))
551 if rv.Kind() != reflect.Struct {
552 panic("not a struct")
555 var s string
557 for i := 0; i < rv.NumField(); i++ {
558 f := rv.Field(i)
560 s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())
563 return s